package org.jeecg.modules.demo.cashier.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.saobei.open.sdk.model.response.trade.SaobeiBarcodePayResponse;
import com.saobei.open.sdk.model.response.trade.SaobeiTradeQueryResponse;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.demo.basemembervip.entity.BaseMemberVip;
import org.jeecg.modules.demo.basemembervip.service.IBaseMemberVipService;
import org.jeecg.modules.demo.basemembervipcoupon.entity.BaseMemberVipCoupon;
import org.jeecg.modules.demo.basemembervipcoupon.service.IBaseMemberVipCouponService;
import org.jeecg.modules.demo.baseorde.entity.BaseOrder;
import org.jeecg.modules.demo.baseorde.entity.BaseOrderCommodityJson;
import org.jeecg.modules.demo.baseorde.service.IBaseOrderService;
import org.jeecg.modules.demo.baseordercommodity.entity.BaseOrderCommodity;
import org.jeecg.modules.demo.baseordercommodity.service.IBaseOrderCommodityService;
import org.jeecg.modules.demo.baseordercommoditywriteoff.entity.BaseOrderCommodityWriteoff;
import org.jeecg.modules.demo.baseordercommoditywriteoff.service.IBaseOrderCommodityWriteoffService;
import org.jeecg.modules.demo.baseorderproject.entity.BaseOrderProject;
import org.jeecg.modules.demo.baseorderproject.service.IBaseOrderProjectService;
import org.jeecg.modules.demo.baseorderservicewriteoff.entity.BaseOrderServiceWriteoff;
import org.jeecg.modules.demo.baseorderservicewriteoff.service.IBaseOrderServiceWriteoffService;
import org.jeecg.modules.demo.baseorderwriteoffrecord.entity.BaseOrderWriteoffRecord;
import org.jeecg.modules.demo.baseorderwriteoffrecord.service.IBaseOrderWriteoffRecordService;
import org.jeecg.modules.demo.basepayorder.entity.BasePayOrder;
import org.jeecg.modules.demo.basepayorder.service.IBasePayOrderService;
import org.jeecg.modules.demo.basepreorder.entity.BasePreOrder;
import org.jeecg.modules.demo.basepreorder.service.IBasePreOrderService;
import org.jeecg.modules.demo.baseselforder.entity.BaseSelfOrder;
import org.jeecg.modules.demo.baseselforder.service.IBaseSelfOrderService;
import org.jeecg.modules.demo.basestaffstatus.entity.BaseStaffStatus;
import org.jeecg.modules.demo.basestaffstatus.service.IBaseStaffStatusService;
import org.jeecg.modules.demo.basestaffstatusspecial.entity.BaseStaffStatusSpecial;
import org.jeecg.modules.demo.basestaffstatusspecial.service.IBaseStaffStatusSpecialService;
import org.jeecg.modules.demo.blancechangerecord.entity.BalanceChangeRecord;
import org.jeecg.modules.demo.blancechangerecord.service.IBalanceChangeRecordService;
import org.jeecg.modules.demo.cashier.service.CashierService;
import org.jeecg.modules.demo.castcardrecord.entity.CastCardRecord;
import org.jeecg.modules.demo.castcardrecord.service.ICastCardRecordService;
import org.jeecg.modules.demo.commoditygroup.entity.CommodityGroup;
import org.jeecg.modules.demo.commoditygroup.service.ICommodityGroupService;
import org.jeecg.modules.demo.commoditymanagement.entity.CommodityInfo;
import org.jeecg.modules.demo.commoditymanagement.entity.CommodityManagement;
import org.jeecg.modules.demo.commoditymanagement.service.ICommodityManagementService;
import org.jeecg.modules.demo.instoragedetail.entity.InStorageDetail;
import org.jeecg.modules.demo.issuingrecords.entity.IssuingRecords;
import org.jeecg.modules.demo.issuingrecords.service.IIssuingRecordsService;
import org.jeecg.modules.demo.levelset.entity.LevelSet;
import org.jeecg.modules.demo.levelset.service.ILevelSetService;
import org.jeecg.modules.demo.memberenterstorerecord.entity.MemberEnterStoreRecord;
import org.jeecg.modules.demo.memberenterstorerecord.service.IMemberEnterStoreRecordService;
import org.jeecg.modules.demo.membermanagement.entity.MemberManagement;
import org.jeecg.modules.demo.membermanagement.service.IMemberManagementService;
import org.jeecg.modules.demo.msgtemplatelist.entity.MsgTemplate;
import org.jeecg.modules.demo.msgtemplatelist.service.IMsgTemplateService;
import org.jeecg.modules.demo.outstoragedetail.entity.OutStorageDetail;
import org.jeecg.modules.demo.outstoragedetail.service.IOutStorageDetailService;
import org.jeecg.modules.demo.outstoragemain.entity.OutStorageMain;
import org.jeecg.modules.demo.outstoragemain.service.IOutStorageMainService;
import org.jeecg.modules.demo.projectgroup.entity.ProjectGroup;
import org.jeecg.modules.demo.projectgroup.service.IProjectGroupService;
import org.jeecg.modules.demo.projectmanagement.entity.ProjectManagement;
import org.jeecg.modules.demo.projectmanagement.service.IProjectManagementService;
import org.jeecg.modules.demo.staffmanagement.entity.StaffManagement;
import org.jeecg.modules.demo.staffmanagement.service.IStaffManagementService;
import org.jeecg.modules.demo.stockmanage.entity.StockManage;
import org.jeecg.modules.demo.stockmanage.service.IStockManageService;
import org.jeecg.modules.demo.storageoutindetail.entity.StorageOutinDetail;
import org.jeecg.modules.demo.storageoutindetail.service.IStorageOutinDetailService;
import org.jeecg.modules.demo.storeinfo.entity.StoreInfo;
import org.jeecg.modules.demo.storeinfo.service.IStoreInfoService;
import org.jeecg.modules.demo.storestaffreward.entity.StoreStaffReward;
import org.jeecg.modules.demo.storestaffreward.service.IStoreStaffRewardService;
import org.jeecg.modules.saobei.Saobei;
import org.jeecg.modules.util.*;
import org.jeecg.modules.weixin.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 收银台
 */
@RestController
@RequestMapping("/cashier")
@Slf4j
public class CashierController {

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private CashierService cashierService;
    @Autowired
    private IMemberManagementService memberManagementService;
    @Autowired
    private IStockManageService stockManageService;
    @Autowired
    private IStaffManagementService staffManagementService;
    @Autowired
    private ICommodityGroupService commodityGroupService;
    @Autowired
    private ICommodityManagementService commodityManagementService;
    @Autowired
    private IProjectGroupService projectGroupService;
    @Autowired
    private IProjectManagementService projectManagementService;
    @Autowired
    private IBaseOrderService baseOrderService;
    @Autowired
    private IBaseOrderCommodityService baseOrderCommodityService;
    @Autowired
    private IBaseOrderProjectService baseOrderProjectService;
    @Autowired
    private IBaseOrderServiceWriteoffService baseOrderServiceWriteoffService;
    @Autowired
    private IBaseOrderCommodityWriteoffService baseOrderCommodityWriteoffService;
    @Autowired
    private IBasePreOrderService basePreOrderService;
    @Autowired
    private IStoreInfoService storeInfoService;
    @Autowired
    private ILevelSetService levelSetService;
    @Autowired
    private IBaseMemberVipService baseMemberVipService;
    @Autowired
    private IBaseMemberVipCouponService baseMemberVipCouponService;
    @Autowired
    private IBaseOrderWriteoffRecordService baseOrderWriteoffRecordService;
    @Autowired
    private IBasePayOrderService basePayOrderService;
    @Autowired
    private IIssuingRecordsService issuingRecordsService;
    @Autowired
    private IBaseStaffStatusService baseStaffStatusService;
    @Autowired
    private IBaseStaffStatusSpecialService baseStaffStatusSpecialService;
    @Autowired
    private IOutStorageMainService outStorageMainService;
    @Autowired
    private IOutStorageDetailService outStorageDetailService;
    @Autowired
    private IStorageOutinDetailService storageOutinDetailService;
    @Autowired
    private IBaseSelfOrderService baseSelfOrderService;
    @Autowired
    private IMsgTemplateService msgTemplateListService;
    @Autowired
    private ICastCardRecordService castCardRecordService;
    @Autowired
    private IBalanceChangeRecordService blanceChangeRecordService;
    @Autowired
    private IMemberEnterStoreRecordService memberEnterStoreRecordService;
    @Autowired
    private IStoreStaffRewardService storeStaffRewardService;

    /**
     * 会员搜索（用姓名/手机号/备注搜索会员，返回会员id，姓名、手机号、备注拼接的文字）
     * 参数：keyword
     */
    @ApiOperation(value = "收银台-搜索会员", notes = "收银台-搜索会员")
    @PostMapping("/searchMember")
    public Result<?> searchMember(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        if("13000000000".equals(map.get("keyword"))){
            List<Map<String, Object>> maps =new ArrayList<>();
            HashMap<String, Object> sanKe = new HashMap<>();
            sanKe.put("id","13000000000");
            maps.add(sanKe);
            return Result.OK(maps);
        }else{
            return Result.OK(cashierService.searchMember(map));
        }
    }

    /**
     * 列出销售和技师
     */
    @ApiOperation(value = "收银台-列出员工", notes = "收银台-列出员工")
    @PostMapping("/listEmpolyee")
    public Result<?> listEmpolyee(HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        List<StaffManagement> list = staffManagementService.list(new QueryWrapper<StaffManagement>().eq("store_id", storeId));
        List<Map<String, Object>> result = new ArrayList<>();
        for (StaffManagement s : list) {
            String employeeId = s.getEmployeeId();
            Map<String, Object> m = new HashMap<>();
            m.put("id", s.getId());
            m.put("name", s.getName());
            BaseStaffStatus bss = baseStaffStatusService.getById(employeeId);
            m.put("position", bss.getStatusName());
            m.put("tradeActor", bss.getTradeActor());

//            List<Map<String, Object>> rewards = new ArrayList<>();
//            List<StoreStaffReward> list1 = storeStaffRewardService.list(new QueryWrapper<StoreStaffReward>().eq("trade_actor", employeeId));
//            for (StoreStaffReward r : list1) {
//                Map<String, Object> rm = new HashMap<>();
//                rm.put("id", r.getId());
//                rm.put("type", r.getType());
//                rm.put("relateId", r.getRelateId());
//                rm.put("relateName", r.getRelateName());
//                rm.put("shareWay1", r.getShareWay1());
//                rm.put("value1", r.getValue1());
//                rm.put("shareWay2", r.getShareWay2());
//                rm.put("value2", r.getValue2());
//                rewards.add(rm);
//            }
//
//            m.put("rewards", rewards);
            result.add(m);

        }

        return Result.OK(result);
    }


    /**
     * 列出销售和技师
     */
    @ApiOperation(value = "收银台-列出提成", notes = "收银台-列出提成")
    @PostMapping("/listReward")
    public Result<?> listReward(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        String staffId = map.get("staffId") == null ? null : String.valueOf(map.get("staffId"));
        String relateId = map.get("relateId") == null ? null : String.valueOf(map.get("relateId"));
        if (StringUtils.isBlank(staffId)) {
            return Result.error("缺少员工标识");
        }
        if (StringUtils.isBlank(relateId)) {
            return Result.error("缺少产品标识");
        }

        StaffManagement staff = staffManagementService.getById(staffId);
        List<Map<String, Object>> result = new ArrayList<>();
        if (staff == null) {
            return Result.error("员工标识错误,没有员工");
        }
        String employeeId = staff.getEmployeeId();
        if (StringUtils.isEmpty(employeeId)) {
            return Result.error("员工设置错误,没有身份");
        }

        List<StoreStaffReward> list1 = storeStaffRewardService.list(new QueryWrapper<StoreStaffReward>().eq("trade_actor", employeeId).eq("relate_id", relateId));
        for (StoreStaffReward r : list1) {
            Map<String, Object> rm = new HashMap<>();
            rm.put("id", r.getId());
            rm.put("type", r.getType());
            rm.put("relateId", r.getRelateId());
            rm.put("relateName", r.getRelateName());
            rm.put("shareWay1", r.getShareWay1());
            rm.put("value1", r.getValue1());
            rm.put("shareWay2", r.getShareWay2());
            rm.put("value2", r.getValue2());
            result.add(rm);
        }


        return Result.OK(result);
    }

    /**
     * 会员详情（用会员id和会员类型查详情，返回会员属性以及会员折扣）
     * 参数：*id
     */
    @PostMapping("/getMember")
    public Result<?> getMember(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String id = map.get("id") == null ? null : String.valueOf(map.get("id"));
        if (StringUtils.isEmpty(id)) {
            return Result.error("参数不全");
        }
        MemberManagement member;
        if("13000000000".equals(id)){
            LambdaQueryWrapper<MemberManagement> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(MemberManagement::getPhone,id);
            wrapper.eq(MemberManagement::getStoreId,storeId);
            member = memberManagementService.getOne(wrapper);
        }else{
            member = memberManagementService.getById(id);
        }
        //Map<String, Object> result = cashierService.getMember(map);
        if (!StrUtil.isBlankIfStr(member.getStoreId())) {
            StoreInfo store = storeInfoService.getById(member.getStoreId());
            member.setBelongStore(store.getStoreName());
        }
        Map<String, Object> result = BeanUtils.bean2Map(member);
        String levelId = member.getLevelId();
        if (!org.jeecg.modules.util.StringUtils.isBlank(levelId)) {
            if(StrUtil.isBlank(member.getMyStockId())){ //如果不是股东
                LevelSet byId = levelSetService.getById(levelId);
                result.put("memberDiscount", byId.getDiscount());
            }else{//如果是股东
                StockManage stockManage = stockManageService.getById(member.getMyStockId());
                result.put("memberDiscount", stockManage.getShareholderDiscount());
            }

        }
        List<LevelSet> levelSetList = levelSetService.list(new QueryWrapper<LevelSet>().eq("store_id", storeId));
        for (LevelSet ls : levelSetList) {
            if (ls.getRankNum().equals("1")) {
                if (member.getPhone().equals("13000000000")) {
                    result.put("memberDiscount", ls.getDiscount());
                    if (!ls.getId().equals(member.getMemberLevel())) {
                        member.setLevelId(ls.getId());
                        memberManagementService.updateById(member);
                    }
                }
            }
        }
        if (!StringUtils.isEmpty(member.getMyStockId())) {

            String myStockId = member.getMyStockId();
            StockManage stock = stockManageService.getById(myStockId);
            if (stock != null) {
                result.put("myStock", stock);
            }
        }


        //上级
        if (!StringUtils.isEmpty(member.getStockId())) {

            String stockId = member.getStockId();
            StockManage stock = stockManageService.getById(stockId);
            if (stock != null) {
                result.put("mystockName", stock.getStockName());
            }
        }

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if ("员工".equals(sysUser.getRoleType())) {
            String userId = sysUser.getId();
            StaffManagement staff = staffManagementService.getOne(new QueryWrapper<StaffManagement>().eq("user_id", userId));
            BigDecimal manualDiscount = staff.getManualDiscount() == null ? BigDecimal.ZERO : new BigDecimal(String.valueOf(staff.getManualDiscount()));
            result.put("manualDiscount", manualDiscount);
        } else {
            result.put("manualDiscount", null);
        }

        return Result.OK(result);
    }

    /**
     * 修改会员备注
     * 参数：*id, *remark
     */
    @PostMapping("/updateNormalMemberRemark")
    public Result<?> updateNormalMemberRemark(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String id = map.get("id") == null ? null : String.valueOf(map.get("id"));
        String remark = map.get("remark") == null ? null : String.valueOf(map.get("remark"));
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(remark)) {
            return Result.error("参数不全");
        }

        MemberManagement mm = new MemberManagement();
        mm.setId(id);
        mm.setRemark(remark);
        memberManagementService.updateById(mm);
        return Result.OK();
    }


    /**
     * 修改股东备注
     * 参数：*id, *remark
     */
    @PostMapping("/updateStockMemberRemark")
    public Result<?> updateStockMemberRemark(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String id = map.get("id") == null ? null : String.valueOf(map.get("id"));
        String remark = map.get("remark") == null ? null : String.valueOf(map.get("remark"));
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(remark)) {
            return Result.error("参数不全");
        }

        MemberManagement mm = memberManagementService.getById(id);

        StockManage sm = new StockManage();
        sm.setId(mm.getMyStockId());
        sm.setRemark(remark);
        stockManageService.updateById(sm);
        return Result.OK();
    }

    /**
     * 员工搜索（用工号/姓名/手机号搜索员工，返回员工id，工号、姓名、手机号拼接的文字）
     * 参数：keyword
     */
    @PostMapping("/searchStaff")
    public Result<?> searchStaff(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String keyword = map.get("keyword") == null ? null : String.valueOf(map.get("keyword"));

        List<StaffManagement> list = staffManagementService.list(new QueryWrapper<StaffManagement>()
                .eq("store_id", storeId)
                .and(StringUtils.isNotEmpty(keyword), i -> {
                    i.like("name", keyword)
                            .or().like("contact", keyword)
                            .or().like("job_number", keyword);
                }));

        List<Map<String, Object>> result = list.stream().map(o -> {
            Map<String, Object> m = new HashMap<>();
            m.put("id", o.getId());
            m.put("jobNumber", o.getJobNumber());
            m.put("name", o.getName());
            m.put("contact", o.getContact());
            m.put("content", o.getJobNumber() + " " + o.getName() + " " + o.getContact());
            return m;
        }).collect(Collectors.toList());

        return Result.OK(result);
    }

    /**
     * 员工搜索（用工号/姓名/手机号搜索员工，返回员工id，工号、姓名、手机号拼接的文字）（包含选项：无）
     * 参数：keyword
     */
    @PostMapping("/searchStaff2")
    public Result<?> searchStaff2(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String keyword = map.get("keyword") == null ? null : String.valueOf(map.get("keyword"));

        List<StaffManagement> list = staffManagementService.list(new QueryWrapper<StaffManagement>()
                .eq("store_id", storeId)
                .and(StringUtils.isNotEmpty(keyword), i -> {
                    i.like("name", keyword)
                            .or().like("contact", keyword)
                            .or().like("job_number", keyword);
                }));

        List<Map<String, Object>> result = list.stream().map(o -> {
            Map<String, Object> m = new HashMap<>();
            m.put("id", o.getId());
            m.put("jobNumber", o.getJobNumber());
            m.put("name", o.getName());
            m.put("contact", o.getContact());
            m.put("content", o.getJobNumber() + " " + o.getName() + " " + o.getContact());
            return m;
        }).collect(Collectors.toList());

        if (StringUtils.isEmpty(keyword)) {
            Map<String, Object> m1 = new HashMap<>();
            m1.put("id", "");
            m1.put("jobNumber", null);
            m1.put("name", null);
            m1.put("contact", null);
            m1.put("content", "无");
            result.add(0, m1);
        }

        return Result.OK(result);
    }

    /**
     * 商品分类列表
     * 参数：
     */
    @PostMapping("/listCommodityGroup")
    public Result<?> listCommodityGroup(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);

        List<CommodityGroup> list = commodityGroupService.list(new QueryWrapper<CommodityGroup>()
                .eq("store_id", storeId));
        return Result.OK(list);
    }

    /**
     * 商品列表
     * 参数：*groupId
     */
    @PostMapping("/listCommodity")
    public Result<?> listCommodity(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String groupId = map.get("groupId") == null ? null : String.valueOf(map.get("groupId"));
        if (StringUtils.isEmpty(groupId)) {
            return Result.error("参数不全");
        }

        List<CommodityManagement> list = commodityManagementService.list(new QueryWrapper<CommodityManagement>()
                .eq("store_id", storeId)
                .eq("group_id", groupId)
                .eq("status", "1")
                .orderByDesc("weight"));
        List<CommodityManagement> result = new ArrayList<>(list);
        for (CommodityManagement c : list) {
            Object o = map.get("keyword");
            if (o != null) {
                String keyword = o.toString();
                if (!c.getTradeName().contains(keyword)) {
                    result.remove(c);
                }
            }
        }
        return Result.OK(result);
    }

    /**
     * 项目分类列表
     * 参数：
     */
    @PostMapping("/listProjectGroup")
    public Result<?> listProjectGroup(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);

        List<ProjectGroup> list = projectGroupService.list(new QueryWrapper<ProjectGroup>()
                .eq("store_id", storeId));
        return Result.OK(list);
    }

    /**
     * 项目列表
     * 参数：*groupId
     */
    @PostMapping("/listProject")
    public Result<?> listProject(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String groupId = map.get("groupId") == null ? null : String.valueOf(map.get("groupId"));
        if (StringUtils.isEmpty(groupId)) {
            return Result.error("参数不全");
        }

        List<ProjectManagement> list = projectManagementService.list(new QueryWrapper<ProjectManagement>()
                .eq("store_id", storeId)
                .eq("group_id", groupId)
                .eq("is_activate", "1")
                .orderByDesc("project_weight"));
        List<ProjectManagement> result = new ArrayList<>(list);
        for (ProjectManagement p : list) {
            Object o = map.get("keyword");
            if (o != null) {
                String keyword = o.toString();
                if (!p.getProjectName().contains(keyword)) {
                    result.remove(p);
                }
            }
        }
        return Result.OK(result);
    }

    /**
     * 优惠券列表（根据已选择的优惠券判断其他优惠券是否还可继续叠加）
     * 参数：*memberId, *totalCanUseDiscountAmount, *useMemberDiscount, couponList[]
     * couponList[]: *id, *num
     */
    @PostMapping("/listCoupon")
    public Result<?> listCoupon(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);

        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String totalCanUseDiscountAmountStr = map.get("totalCanUseDiscountAmount") == null ? null : String.valueOf(map.get("totalCanUseDiscountAmount"));
        String useMemberDiscountStr = map.get("useMemberDiscount") == null ? null : String.valueOf(map.get("useMemberDiscount"));
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(totalCanUseDiscountAmountStr) || StringUtils.isEmpty(useMemberDiscountStr)) {
            return Result.error("参数不全");
        }
        List<Map<String, Object>> couponList = map.get("couponList") == null ? new ArrayList<>() : (List<Map<String, Object>>) map.get("couponList");

        List<Map<String, Object>> listCoupon1 = cashierService.listCoupon1(map);
        List<Map<String, Object>> listCoupon2 = cashierService.listCoupon2(map);
        List<Map<String, Object>> listCoupon3 = cashierService.listCoupon3(map);
        List<Map<String, Object>> result = new ArrayList<>();

        if (couponList.size() == 0) {
            listCoupon1.forEach(m -> m.put("disabled", false));
            result.addAll(listCoupon1);
            result.addAll(listCoupon2);
            result.addAll(listCoupon3);
            return Result.OK(result);
        }
        for (Map<String, Object> m : couponList) {
            boolean couponInList1 = false;
            Map<String, Object> coupon = null;
            for (Map<String, Object> m1 : listCoupon1) {
                if (String.valueOf(m.get("id")).equals(String.valueOf(m1.get("id")))) {
                    coupon = m1;
                    couponInList1 = true;
                }
            }
            if (!couponInList1) {
                return Result.error("使用了不可用的优惠劵，请重新选择");
            }
            int num = m.get("num") == null ? 0 : Integer.parseInt(String.valueOf(m.get("num")));
            int couponNum = coupon.get("num") == null ? 0 : Integer.parseInt(String.valueOf(coupon.get("num")));
            if (num > couponNum) {
                return Result.error("优惠劵：" + coupon.get("ticketName") + "，使用数量超过持有数量，请重新选择");
            }
        }

        List<Map<String, Object>> checkedCoupons = listCoupon1.stream().filter(o -> {
            for (Map<String, Object> m : couponList) {
                if (String.valueOf(o.get("id")).equals(String.valueOf(m.get("id")))) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());

        listCoupon1 = listCoupon1.stream().map(m -> {
            String id = m.get("id") == null ? "" : String.valueOf(m.get("id"));
            String ticketType = m.get("ticketType") == null ? "" : String.valueOf(m.get("ticketType"));
            String isSelectNext = m.get("isSelectNext") == null ? "" : String.valueOf(m.get("isSelectNext"));
            String isSelect = m.get("isSelect") == null ? "" : String.valueOf(m.get("isSelect"));
            m.put("disabled", false);
            if ("1".equals(ticketType)) {
                // 礼品劵
                // 是否可与自身叠加
                boolean overlyingSelf = "0".equals(isSelectNext);
                // 是否可与其他劵叠加
                boolean overlyingOther = "0".equals(isSelect);
                if (!overlyingSelf) {
                    // 已选的自身
                    Map<String, Object> self = checkedCoupons.stream()
                            .filter(o2 -> id.equals(String.valueOf(o2.get("id"))))
                            .findFirst().orElse(null);
                    if (self != null) {
                        int num = m.get("num") == null ? 0 : (Integer) m.get("num");
                        if (num > 1) {
                            m.put("reason", "该劵不能与自身叠加使用，仅能选择1张");
                        }
                    }
                }
                if (!overlyingOther) {
                    // 已选的其他劵的数量
                    long count = checkedCoupons.stream()
                            .filter(o2 -> !id.equals(String.valueOf(o2.get("id"))))
                            .count();
                    if (count > 0) {
                        m.put("disabled", true);
                        m.put("reason", "该劵不能与其他劵叠加使用");
                    }
                }
            }
            return m;
        }).collect(Collectors.toList());

        result.addAll(listCoupon1);
        result.addAll(listCoupon2);
        result.addAll(listCoupon3);
        return Result.OK(result);
    }

    /**
     * 可用优惠券列表（根据优惠券使用条件）
     * 参数：*memberId, *totalAmount
     */
    @PostMapping("/listCoupon1")
    public Result<?> listCoupon1(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String totalCanUseDiscountAmountStr = map.get("totalCanUseDiscountAmount") == null ? null : String.valueOf(map.get("totalCanUseDiscountAmount"));
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(totalCanUseDiscountAmountStr)) {
            return Result.error("参数不全");
        }

        return Result.OK(cashierService.listCoupon1(map));
    }

    /**
     * 不可用优惠券列表（根据优惠券使用条件）
     * 参数：*memberId, *totalAmount
     */
    @PostMapping("/listCoupon2")
    public Result<?> listCoupon2(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String totalCanUseDiscountAmountStr = map.get("totalCanUseDiscountAmount") == null ? null : String.valueOf(map.get("totalCanUseDiscountAmount"));
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(totalCanUseDiscountAmountStr)) {
            return Result.error("参数不全");
        }

        return Result.OK(cashierService.listCoupon2(map));
    }

    /**
     * 已失效优惠券列表（根据优惠券使用条件）
     * 参数：*memberId
     */
    @PostMapping("/listCoupon3")
    public Result<?> listCoupon3(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        if (StringUtils.isEmpty(memberId)) {
            return Result.error("参数不全");
        }

        return Result.OK(cashierService.listCoupon3(map));
    }

    /**
     * 计算总价、优惠金额（根据优惠券使用情况计算总优惠及各商品优惠）
     * 参数：*memberId, *useMemberDiscount(是否使用会员折扣), *memberDiscount(会员折扣), *commodityList[](商品列表), couponList[](优惠券id列表), reduction(手动优惠金额)
     * couponList[]: *id, *num
     * commodityList：*id(商品/项目id), *type(1.商品2.项目), *count(个数), free(是否赠送：1.是0.否), staffId(提成归属员工id)
     */
    @PostMapping("/compute")
    public Result<?> compute(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String useMemberDiscount = map.get("useMemberDiscount") == null ? null : String.valueOf(map.get("useMemberDiscount"));
        List<Map<String, Object>> commodityList = (List<Map<String, Object>>) map.get("commodityList");
        List<Map<String, Object>> couponList = (List<Map<String, Object>>) map.get("couponList");
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(useMemberDiscount) || CollectionUtils.isEmpty(commodityList)) {
            return Result.error("参数不全");
        }
        String reductionStr = map.get("reduction") == null ? "0" : String.valueOf(map.get("reduction"));
        // 手动优惠金额
        BigDecimal reduction = new BigDecimal(reductionStr);

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if ("员工".equals(sysUser.getRoleType())) {
            String userId = sysUser.getId();
            StaffManagement staff = staffManagementService.getOne(new QueryWrapper<StaffManagement>().eq("user_id", userId));
            BigDecimal manualDiscount = staff.getManualDiscount() == null ? BigDecimal.ZERO : new BigDecimal(String.valueOf(staff.getManualDiscount()));
            if (reduction.compareTo(manualDiscount) > 0) {
                return Result.error("手动优惠金额超出员工可支配上限：" + manualDiscount + "元，请调整手动优惠金额");
            }
        }

        return Result.OK(cashierService.compute(map));
    }

    /**
     * 挂单
     * 参数：*memberId, *useMemberDiscount(是否使用会员折扣), *memberDiscount(会员折扣), *commodityList[](商品列表), couponList[](优惠券id列表), reduction(手动优惠金额), preOrderId(挂单id，传了做更新)
     * couponList[]: *id, *num
     * commodityList：*id(商品/项目id), *type(1.商品2.项目), *count(个数), free(是否赠送：1.是0.否), staffId(提成归属员工id)
     */
    @PostMapping("/savePreOrder")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> savePreOrder(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String useMemberDiscount = map.get("useMemberDiscount") == null ? null : String.valueOf(map.get("useMemberDiscount"));
        List<Map<String, Object>> commodityList = (List<Map<String, Object>>) map.get("commodityList");
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(useMemberDiscount) || CollectionUtils.isEmpty(commodityList)) {
            return Result.error("参数不全");
        }
        String remark = map.get("remark") == null ? null : String.valueOf(map.get("remark"));
        String preOrderId = map.get("preOrderId") == null ? null : String.valueOf(map.get("preOrderId"));
        BasePreOrder preOrder = basePreOrderService.getById(preOrderId);
        // 老挂单的商品/项目信息，数据格式同commodityList
        JSONArray commodityList1 = null;
        if (preOrder != null) {
            String jsonStr = preOrder.getJsonStr();
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            commodityList1 = jsonObject.getJSONArray("commodityList");
        }

        Map<String, Object> compute = cashierService.compute(map);

        MemberManagement mm = memberManagementService.getById(memberId);

        StringBuilder sb = new StringBuilder();
        for (Map<String, Object> m : commodityList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String type = m.get("type") == null ? null : String.valueOf(m.get("type"));
            String countStr = m.get("count") == null ? "0" : String.valueOf(m.get("count"));
            int count = Integer.parseInt(countStr);

            if ("1".equals(type)) {
                CommodityManagement commodity = commodityManagementService.getById(id);
                sb.append("商品：").append(commodity.getTradeName()).append(" x").append(countStr).append("，");

                // 挂单时要减库存
                if (commodityList1 != null) {
                    // 更新挂单的话，要重新计算减库存数量
                    for (int i = 0; i < commodityList1.size(); i++) {
                        JSONObject c = commodityList1.getJSONObject(i);
                        if ("1".equals(c.getString("type")) && StringUtils.equals(id, c.getString("id"))) {
                            String countStr1 = c.get("count") == null ? "0" : String.valueOf(c.get("count"));
                            int count1 = Integer.parseInt(countStr1);
                            commodity.setInventory(commodity.getInventory() + count1);
                        }
                    }
                }
                if (commodity.getInventory() < count) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("商品：" + commodity.getTradeName() + "库存不足（剩余" + commodity.getInventory() + "个），请重新选择商品");
                }
                commodity.setInventory(commodity.getInventory() - count);
                if (commodity.getInventory() == 0) {
                    commodity.setStatus("2");
                    // 模板消息
                    try {
                        StoreInfo store = storeInfoService.getById(storeId);
                        if (store != null) {
                            String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
                            String xcxAppId = store.getXcxAppId();
                            String xcxAppSecret = store.getXcxAppSecret();
                            if (bossGzhOpenId == null) {
                                log.info("库存不足提醒模板推送失败，老板未绑定公众号");
                            } else {
                                if (store == null) {
                                    log.info("库存不足提醒模板推送失败，未查到店铺信息");
                                } else {
                                    String gzhAppId = store.getGzhAppId();
                                    String gzhAppSecret = store.getGzhAppSecret();
                                    if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                                        log.info("库存不足提醒模板推送失败，店铺未绑定公众号");
                                    } else {
                                        String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                                        String result1 = HttpUtils.sendGet(url1);
                                        JSONObject resultJson1 = JSON.parseObject(result1);
                                        String errcode = resultJson1.getString("errcode");
                                        if (errcode != null && !"0".equals(errcode)) {
                                            log.info("库存不足提醒模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                                        } else {
                                            String accessToken = resultJson1.getString("access_token");
                                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                                            MsgTemplate msgTemplate = msgTemplateListService.getByTitle("库存不足提醒", storeId);
                                            String templateId = msgTemplate.getTemplateId();
                                            util.inventoryInsufficientNotice(templateId, bossGzhOpenId, commodity.getTradeName(), String.valueOf(commodity.getInventory()), sdf.format(new Date()), xcxAppId, "", accessToken);
                                            log.info("库存不足提醒模板推送成功");
                                        }
                                    }
                                }
                            }
                        }

                    } catch (Exception e) {
                        log.error("库存不足提醒模板推送失败，发生异常", e);
                    }
                }
                commodityManagementService.updateById(commodity);
            } else {
                ProjectManagement project = projectManagementService.getById(id);
                sb.append("项目：").append(project.getProjectName()).append(" x").append(countStr).append("，");
            }
        }
        String consumeInfo = "";
        if (sb.length() > 0) {
            consumeInfo = sb.deleteCharAt(sb.length() - 1).toString();
        }

        BasePreOrder bpo = new BasePreOrder();
        bpo.setMemberName(mm.getName());
        bpo.setMemberPhone(mm.getPhone());
        bpo.setTotalAmount(String.valueOf(compute.get("totalAmount")));
        bpo.setConsumeInfo(consumeInfo);
        bpo.setRemark(remark);
        bpo.setStoreId(storeId);
        bpo.setJsonStr(JSON.toJSONString(map));
        if (StringUtils.isEmpty(preOrderId)) {
            basePreOrderService.save(bpo);
        } else {
            bpo.setId(preOrderId);
            basePreOrderService.updateById(bpo);
        }

        return Result.OK(bpo.getId());
    }

    /**
     * 取单列表
     */
    @PostMapping("/listPreOrder")
    public Result<?> listPreOrder(HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }

        List<BasePreOrder> list = basePreOrderService.list(new QueryWrapper<BasePreOrder>()
                .eq("store_id", storeId)
//                .orderByDesc("update_time")
                .orderByDesc("create_time"));
        List<Map<String, Object>> result = list.stream().map(o -> {
            Map<String, Object> m = ToolsUtils.objectToMap(o);
            m.put("json", JSON.parse(o.getJsonStr()));
            return m;
        }).collect(Collectors.toList());
        return Result.OK(result);
    }

    /**
     * 取消挂单
     */
    @PostMapping("/deletePreOrder")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> deletePreOrder(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }

        String id = map.get("id") == null ? null : String.valueOf(map.get("id"));
        if (StringUtils.isEmpty(id)) {
            return Result.error("参数不全");
        }
        BasePreOrder bpo = basePreOrderService.getById(id);
        JSONObject json = JSON.parseObject(bpo.getJsonStr());
        JSONArray commodityList = json.getJSONArray("commodityList");
        for (int i = 0; i < commodityList.size(); i++) {
            JSONObject m = commodityList.getJSONObject(i);
            String cid = m.getString("id");
            String type = m.getString("type");
            String countStr = m.getString("count");
            int count = Integer.parseInt(countStr);

            if ("1".equals(type)) {
                CommodityManagement commodity = commodityManagementService.getById(cid);
                commodity.setInventory(commodity.getInventory() + count);
                commodityManagementService.updateById(commodity);
            }
        }

        basePreOrderService.removeById(id);
        return Result.OK("删除成功");
    }

    /**
     * 订单保存（开单、支付）
     * 参数：*memberId, *payType(付款方式，中文), *totalAmount(订单金额), *totalDiscountAmount(优惠金额), *realAmount(实付金额)
     * , *commodityList[](商品列表), couponList[](优惠券id列表), remark(备注), preOrderId(挂单id，开单时要删除对应的挂单)
     * , balanceAmount(选择其他支付方式时，使用一部分会员余额), stockBalanceAmount(选择其他支付方式时，使用一部分股本余额)
     * , *useMemberDiscount(是否使用会员折扣), *memberDiscount(会员折扣), reduction(手动优惠金额)
     * couponList[]: 与listCoupon接口返回值一致(只传被使用的优惠劵)
     * commodityList：与compute接口返回值一致
     */
    @PostMapping("/saveOrder")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> saveOrder(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String payType = map.get("payType") == null ? null : String.valueOf(map.get("payType"));
        String totalAmount = map.get("totalAmount") == null ? null : String.valueOf(map.get("totalAmount"));
        String totalDiscountAmount = map.get("totalDiscountAmount") == null ? null : String.valueOf(map.get("totalDiscountAmount"));
        String realAmount = map.get("realAmount") == null ? null : String.valueOf(map.get("realAmount"));
        List<Map<String, Object>> commodityList = (List<Map<String, Object>>) map.get("commodityList");
        String useMemberDiscountStr = map.get("useMemberDiscount") == null ? null : String.valueOf(map.get("useMemberDiscount"));
        String memberDiscountStr = map.get("memberDiscount") == null ? null : String.valueOf(map.get("memberDiscount"));
        List<String> list = new ArrayList<>();
        if (StringUtils.isEmpty(memberId)) {
            list.add("memberId");
        }
        if (StringUtils.isEmpty(payType)) {
            list.add("payType");
        }
        if (StringUtils.isEmpty(totalAmount)) {
            list.add("totalmount");
        }
        if (StringUtils.isEmpty(totalDiscountAmount)) {
            list.add("totalDiscountAmount");
        }
        if (StringUtils.isEmpty(realAmount)) {
            list.add("realAmount");
        }
        if (CollectionUtils.isEmpty(commodityList)) {
            list.add("commodityList");
        }
        if (StringUtils.isEmpty(useMemberDiscountStr)) {
            list.add("useMemberDiscount");
        }
//        if ( StringUtils.isEmpty(memberDiscountStr)) {
//            list.add("memberDiscount");
//        }
        if (list.size() > 0) {

            return Result.error(list + "参数不全");
        }
        MemberManagement vMemberManagement = memberManagementService.getById(memberId);
        if (StringUtils.isEmpty(vMemberManagement.getPhone())) {
            log.info("saveOrder:未授权手机号，不允许下单！");
            return Result.error("未授权手机号，不允许下单！");
        }
        List<Map<String, Object>> couponList = map.get("couponList") == null ? new ArrayList<>() : (List<Map<String, Object>>) map.get("couponList");
        String remark = map.get("remark") == null ? null : String.valueOf(map.get("remark"));
        String preOrderId = map.get("preOrderId") == null ? null : String.valueOf(map.get("preOrderId"));
        BigDecimal realAmountDecimal = new BigDecimal(realAmount);
        String balanceAmountStr = map.get("balanceAmount") == null ? "0" : String.valueOf(map.get("balanceAmount"));
        BigDecimal balanceAmount = new BigDecimal(balanceAmountStr);
        String stockBalanceAmountStr = map.get("stockBalanceAmount") == null ? "0" : String.valueOf(map.get("stockBalanceAmount"));
        BigDecimal stockBalanceAmount = new BigDecimal(stockBalanceAmountStr);
        boolean useMemberDiscount = "1".equals(useMemberDiscountStr);
        BigDecimal memberDiscount = memberDiscountStr == null ? BigDecimal.TEN : new BigDecimal(memberDiscountStr);
        String reductionStr = map.get("reduction") == null ? "0" : String.valueOf(map.get("reduction"));
        BigDecimal reduction = new BigDecimal(reductionStr);
        String outTradeNo = map.get("outTradeNo") == null ? null : String.valueOf(map.get("outTradeNo"));

        BasePreOrder preOrder = basePreOrderService.getById(preOrderId);
        // 老挂单的商品/项目信息，数据格式同commodityList
        JSONArray commodityList1 = null;
        if (preOrder != null) {
            String jsonStr = preOrder.getJsonStr();
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            commodityList1 = jsonObject.getJSONArray("commodityList");
        }
        // 开单时要删除对应的挂单
        if (StringUtils.isNotEmpty(preOrderId)) {
            basePreOrderService.removeById(preOrderId);
        }

        MemberManagement mm = memberManagementService.getById(memberId);
        // TODO 二级股东
        // 参与分红的股东
        StockManage dividendStock = null;

        BaseOrder order = new BaseOrder();
        order.setOrderCode(ToolsUtils.getBillNo("SO"));
        order.setOrderType("01");
        order.setPayType(payType);
        order.setOrderStatus("1");
        order.setStoreId(storeId);
        order.setStoreName(storeInfoService.getById(storeId).getStoreName());
        order.setMemberId(memberId);
        order.setMemberName(mm.getName());
        order.setMemberPhone(mm.getPhone());
        order.setMemberNickName(mm.getNickName());
        order.setMemberHeadPortrait(mm.getHeadPortrait());
        order.setMemberLevel(levelSetService.getById(mm.getLevelId()).getRankName());
        if ("1".equals(mm.getStatus())) {
            dividendStock = stockManageService.getById(mm.getStockId());
            if (dividendStock != null) {
                order.setStockName(dividendStock.getStockName());
                MemberManagement dividendStockMember = memberManagementService.getOne(new QueryWrapper<MemberManagement>().eq("store_id", storeId).eq("my_stock_id", dividendStock.getId()));
                order.setStockPhone(dividendStockMember.getPhone());

            }
        }
        order.setTotalAmount(Double.parseDouble(totalAmount));
        order.setTotalDiscountAmount(Double.parseDouble(totalDiscountAmount));
        order.setRealAmount(Double.parseDouble(realAmount));
        order.setMemberDiscount(useMemberDiscount ? memberDiscount.toString() : "未使用会员/股东折扣");
        order.setReduction(reduction.doubleValue());
        order.setWeixinAmount(0.00);
        order.setWeixinAccount(0.00);
        order.setZhifubaoAmount(0.00);
        order.setZhifubaoAccount(0.00);
        order.setBalanceAmount(0.00);
        order.setStockBalanceAmount(0.00);
        order.setChargeAmount(0.00);



        BalanceChangeRecord record = new BalanceChangeRecord();
        record.setMemberId(memberId);
        record.setMemberName(mm.getName());
        record.setMemberPhone(mm.getPhone());
        record.setChangeCode("X");
        record.setStoreId(storeId);
        record.setOrderNo(ToolsUtils.getBillNo("XF"));
        record.setPayCode("");
        record.setTradeMode("");
        record.setTradeTime(Date.from(Instant.now()));
        record.setRemark("");
        record.setId(null);
        record.setCreateBy("");
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateBy(null);
        record.setUpdateBy(null);





        switch (payType) {
            case "扫码支付":
                if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                    if (balanceAmount.compareTo(balance) > 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("会员余额不足，请调整");
                    }


                    mm.setBalance(balance.subtract(balanceAmount).doubleValue());
                    memberManagementService.updateById(mm);


                    record.setAmount(balanceAmount.doubleValue());
                    record.setBalanceType("M");
                    record.setOldValue(balance.doubleValue());
                    record.setNewValue(mm.getBalance());

                    blanceChangeRecordService.save(record);


                }
                if (stockBalanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    StockManage sm = stockManageService.getById(mm.getMyStockId());
                    if (sm == null) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("当前客户不是股东，不可使用股东余额支付");
                    }
                    BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                    BigDecimal stockLowest = new BigDecimal(String.valueOf(sm.getStockLowest()));
                    if (equityBalance.subtract(stockBalanceAmount).compareTo(stockLowest) < 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("股本余额不足（股本最低限额：" + sm.getStockLowest() + "元），请调整");
                    }
                    sm.setEquityBalance(equityBalance.subtract(stockBalanceAmount).doubleValue());
                    stockManageService.updateById(sm);


                    record.setAmount(stockBalanceAmount.doubleValue());
                    record.setBalanceType("S");
                    record.setOldValue(equityBalance.doubleValue());
                    record.setNewValue(sm.getEquityBalance());
                    blanceChangeRecordService.save(record);

                }
                order.setBalanceAmount(balanceAmount.doubleValue());
                order.setStockBalanceAmount(stockBalanceAmount.doubleValue());
                order.setPayCode(outTradeNo);
                order.setWeixinAmount(realAmountDecimal.subtract(balanceAmount).subtract(stockBalanceAmount).doubleValue());
                break;
            case "现金支付":
                if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                    if (balanceAmount.compareTo(balance) > 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("会员余额不足，请调整");
                    }
                    mm.setBalance(balance.subtract(balanceAmount).doubleValue());
                    memberManagementService.updateById(mm);

                    record.setAmount(balanceAmount.doubleValue());
                    record.setBalanceType("M");
                    record.setOldValue(balance.doubleValue());
                    record.setNewValue(mm.getBalance());
                    blanceChangeRecordService.save(record);
                }
                if (stockBalanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    StockManage sm = stockManageService.getById(mm.getMyStockId());
                    if (sm == null) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("当前客户不是股东，不可使用股东余额支付");
                    }
                    BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                    BigDecimal stockLowest = new BigDecimal(String.valueOf(sm.getStockLowest()));
                    if (equityBalance.subtract(stockBalanceAmount).compareTo(stockLowest) < 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("股本余额不足（股本最低限额：" + sm.getStockLowest() + "元），请调整");
                    }
                    sm.setEquityBalance(equityBalance.subtract(stockBalanceAmount).doubleValue());
                    stockManageService.updateById(sm);


                    record.setAmount(stockBalanceAmount.doubleValue());
                    record.setBalanceType("S");
                    record.setOldValue(equityBalance.doubleValue());
                    record.setNewValue(sm.getEquityBalance());
                    blanceChangeRecordService.save(record);
                }
                order.setBalanceAmount(balanceAmount.doubleValue());
                order.setStockBalanceAmount(stockBalanceAmount.doubleValue());
                order.setChargeAmount(realAmountDecimal.subtract(balanceAmount).subtract(stockBalanceAmount).doubleValue());
                break;
            case "支付宝记账":
                if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                    if (balanceAmount.compareTo(balance) > 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("会员余额不足，请调整");
                    }
                    mm.setBalance(balance.subtract(balanceAmount).doubleValue());
                    memberManagementService.updateById(mm);


                    record.setAmount(balanceAmount.doubleValue());
                    record.setBalanceType("M");
                    record.setOldValue(balance.doubleValue());
                    record.setNewValue(mm.getBalance());
                    blanceChangeRecordService.save(record);


                }
                if (stockBalanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    StockManage sm = stockManageService.getById(mm.getMyStockId());
                    if (sm == null) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("当前客户不是股东，不可使用股东余额支付");
                    }
                    BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                    BigDecimal stockLowest = new BigDecimal(String.valueOf(sm.getStockLowest()));
                    if (equityBalance.subtract(stockBalanceAmount).compareTo(stockLowest) < 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("股本余额不足（股本最低限额：" + sm.getStockLowest() + "元），请调整");
                    }
                    sm.setEquityBalance(equityBalance.subtract(stockBalanceAmount).doubleValue());
                    stockManageService.updateById(sm);


                    record.setAmount(stockBalanceAmount.doubleValue());
                    record.setBalanceType("S");
                    record.setOldValue(equityBalance.doubleValue());
                    record.setNewValue(sm.getEquityBalance());
                    blanceChangeRecordService.save(record);
                }
                order.setBalanceAmount(balanceAmount.doubleValue());
                order.setStockBalanceAmount(stockBalanceAmount.doubleValue());
                order.setZhifubaoAccount(realAmountDecimal.subtract(balanceAmount).subtract(stockBalanceAmount).doubleValue());
                break;
            case "微信记账":
                if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                    if (balanceAmount.compareTo(balance) > 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("会员余额不足，请调整");
                    }
                    mm.setBalance(balance.subtract(balanceAmount).doubleValue());
                    memberManagementService.updateById(mm);


                    record.setAmount(balanceAmount.doubleValue());
                    record.setBalanceType("M");
                    record.setOldValue(balance.doubleValue());
                    record.setNewValue(mm.getBalance());
                    blanceChangeRecordService.save(record);
                }
                if (stockBalanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    StockManage sm = stockManageService.getById(mm.getMyStockId());
                    if (sm == null) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("当前客户不是股东，不可使用股东余额支付");
                    }
                    BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                    BigDecimal stockLowest = new BigDecimal(String.valueOf(sm.getStockLowest()));
                    if (equityBalance.subtract(stockBalanceAmount).compareTo(stockLowest) < 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return Result.error("股本余额不足（股本最低限额：" + sm.getStockLowest() + "元），请调整");
                    }
                    sm.setEquityBalance(equityBalance.subtract(stockBalanceAmount).doubleValue());
                    stockManageService.updateById(sm);


                    record.setAmount(stockBalanceAmount.doubleValue());
                    record.setBalanceType("S");
                    record.setOldValue(equityBalance.doubleValue());
                    record.setNewValue(sm.getEquityBalance());
                    blanceChangeRecordService.save(record);

                }
                order.setBalanceAmount(balanceAmount.doubleValue());
                order.setStockBalanceAmount(stockBalanceAmount.doubleValue());
                order.setWeixinAccount(realAmountDecimal.subtract(balanceAmount).subtract(stockBalanceAmount).doubleValue());
                break;
            case "会员余额支付":
                order.setBalanceAmount(Double.parseDouble(realAmount));
                BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                if (realAmountDecimal.compareTo(balance) > 0) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("会员余额不足，请选择其他支付方式");
                }
                mm.setBalance(balance.subtract(realAmountDecimal).doubleValue());
                memberManagementService.updateById(mm);


                record.setAmount(realAmountDecimal.doubleValue());
                record.setBalanceType("M");
                record.setOldValue(balance.doubleValue());
                record.setNewValue(mm.getBalance());
                blanceChangeRecordService.save(record);


                break;
            case "股本余额支付":
                order.setStockBalanceAmount(Double.parseDouble(realAmount));
                StockManage sm = stockManageService.getById(mm.getMyStockId());
                if (sm == null) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("当前客户不是股东，不可使用股东余额支付");
                }
                BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                BigDecimal stockLowest = new BigDecimal(String.valueOf(sm.getStockLowest()));
                if (equityBalance.subtract(realAmountDecimal).compareTo(stockLowest) < 0) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("股本余额不足以支付订单（股本最低限额：" + sm.getStockLowest() + "元），请选择其他支付方式");
                }
                sm.setEquityBalance(equityBalance.subtract(realAmountDecimal).doubleValue());
                stockManageService.updateById(sm);

                record.setAmount(realAmountDecimal.doubleValue());
                record.setBalanceType("S");
                record.setOldValue(equityBalance.doubleValue());
                record.setNewValue(sm.getEquityBalance());
                blanceChangeRecordService.save(record);

                break;
        }
        order.setRemark(remark);

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if ("员工".equals(sysUser.getRoleType())) {
            String userId = sysUser.getId();
            StaffManagement staff = staffManagementService.getOne(new QueryWrapper<StaffManagement>().eq("user_id", userId));
            order.setStaffId(staff.getId());
            order.setStaffName(staff.getName());
            order.setStaffPhone(staff.getContact());
        } else {
            order.setStaffName(sysUser.getRealname());
            order.setStaffPhone(sysUser.getPhone());
        }
        order.setOrderJsonStr(JSON.toJSONString(map));
        baseOrderService.save(order);

        for (Map<String, Object> m : couponList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String numStr = m.get("num") == null ? "0" : String.valueOf(m.get("num"));
            int num = Integer.parseInt(numStr);
            BaseMemberVipCoupon bmvc = baseMemberVipCouponService.getById(id);
            if (num > bmvc.getNum()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error("优惠劵名称：" + bmvc.getTicketName() + "，优惠劵使用数量超出了持有数量");
            }
            bmvc.setNum(bmvc.getNum() - num);
            baseMemberVipCouponService.updateById(bmvc);

            // 处理优惠劵使用情况、发卡记录到店情况
            BaseMemberVip bmv = baseMemberVipService.getById(bmvc.getMemberVipId());
            if ("0".equals(bmv.getUsed())) {
                bmv.setUsed("1");
                baseMemberVipService.updateById(bmv);
                IssuingRecords ir = issuingRecordsService.getById(bmv.getIssuingRecordsId());
                if (ir != null) {
                    ir.setToStoreNum(ir.getToStoreNum() + 1);
                    issuingRecordsService.updateById(ir);
                }
            }
        }
        // 订单总员工销售提成
        BigDecimal commissionMoneyAll = BigDecimal.ZERO;
        // 订单总股东分红
        BigDecimal dividendMoneyAll = BigDecimal.ZERO;
        // 订单总带动营业额
        BigDecimal driveTurnoverAll = BigDecimal.ZERO;

        // 出库记录明细
        List<OutStorageDetail> outStorageDetailList = new ArrayList<>();
        // 出入库明细
        List<StorageOutinDetail> storageOutinDetailList = new ArrayList<>();

        for (Map<String, Object> m : commodityList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String type = m.get("type") == null ? null : String.valueOf(m.get("type"));
            String countStr = m.get("count") == null ? "0" : String.valueOf(m.get("count"));
            BigDecimal count = new BigDecimal(countStr);
            String name = m.get("name") == null ? null : String.valueOf(m.get("name"));
            String specification = m.get("specification") == null ? null : String.valueOf(m.get("specification"));
            String price = m.get("price") == null ? "0" : String.valueOf(m.get("price"));
            String totalPrice = m.get("totalPrice") == null ? "0" : String.valueOf(m.get("totalPrice"));
            String discountAmount = m.get("discountAmount") == null ? "0" : String.valueOf(m.get("discountAmount"));
            String free = m.get("free") == null ? "0" : String.valueOf(m.get("free"));
            String pic = m.get("pic") == null ? null : String.valueOf(m.get("pic"));
            String staffId = m.get("staffId") == null ? null : String.valueOf(m.get("staffId"));

            String staffsStr = m.get("staffs") == null ? null : String.valueOf(m.get("staffs"));

            BigDecimal totalPriceDecimal = new BigDecimal(totalPrice);
            BigDecimal discountAmountDecimal = new BigDecimal(discountAmount);
            BigDecimal realTotalPrice = totalPriceDecimal.subtract(discountAmountDecimal);

            // JSONArray staffs = JSONObject.parseArray(staffsStr);
            staffsStr = staffsStr.replaceAll("=", ":");

            String saleStaffId = null;

            BigDecimal saleTC = BigDecimal.ZERO;

            try {
                String s = JsonUtils.fixFormat(staffsStr);
                JSONArray staffs = JSONObject.parseArray(s);
                for (int i = 0; i < staffs.size(); i++) {
                    JSONObject staff = staffs.getJSONObject(i);
                    String strStaffId = staff.getString("staffId");
                    String strWorkActor = staff.getString("workActor");

                    String strShareWay = staff.getString("shareWay");
                    String strValue = staff.getString("value");
                    if ("1".equals(strWorkActor)) {
                        saleStaffId = strStaffId;
                        if ("1".equals(strShareWay)) {
                            BigDecimal percent = new BigDecimal(strValue);
                            saleTC = percent.multiply(realTotalPrice).divide(BigDecimal.valueOf(100));
                            giveStaffMoney(strStaffId, "1", saleTC);
                        } else {
                            saleTC = count.multiply(new BigDecimal(strValue));
                            giveStaffMoney(strStaffId, "1", saleTC);
                        }
                    } else if ("2".equals(strWorkActor)) {
                        if ("1".equals(strShareWay)) {
                            BigDecimal percent = new BigDecimal(strValue);
                            giveStaffMoney(strStaffId, "2", percent.multiply(realTotalPrice).divide(BigDecimal.valueOf(100)));
                        } else {
                            giveStaffMoney(strStaffId, "2", count.multiply(new BigDecimal(strValue)));
                        }
                    }
                }
            } catch (Exception e) {

            }


            // 拿销售提成的员工
            StaffManagement xiaoshouStaff = null;

            if (!StringUtils.isBlank(saleStaffId)) {
                xiaoshouStaff = staffManagementService.getById(saleStaffId);
            }

            if ("1".equals(type)) {
                // ------------------------- 商品 -------------------------
                CommodityManagement cm = commodityManagementService.getById(id);
                if (cm == null) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("选择了不存在的商品");
                }
                if (commodityList1 != null) {
                    // 通过挂单记录开单的话，要重新计算减库存数量
                    for (int i = 0; i < commodityList1.size(); i++) {
                        JSONObject c = commodityList1.getJSONObject(i);
                        if ("1".equals(c.getString("type")) && StringUtils.equals(id, c.getString("id"))) {
                            String countStr1 = c.get("count") == null ? "0" : String.valueOf(c.get("count"));
                            int count1 = Integer.parseInt(countStr1);
                            cm.setInventory(cm.getInventory() + count1);
                        }
                    }
                }
                if (cm.getInventory() < count.intValue()) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("商品：" + cm.getTradeName() + "库存不足（剩余" + cm.getInventory() + "个），请重新选择商品");
                }
                cm.setInventory(cm.getInventory() - count.intValue());
                if (cm.getInventory() == 0) {
                    cm.setStatus("2");
                    // 模板消息
                    try {
                        StoreInfo store = storeInfoService.getById(storeId);
                        if (store != null) {
                            String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
                            String xcxAppId = store.getXcxAppId();
                            String xcxAppSecret = store.getXcxAppSecret();
                            if (bossGzhOpenId == null) {
                                log.info("库存不足提醒模板推送失败，老板未绑定公众号");
                            } else {
                                if (store == null) {
                                    log.info("库存不足提醒模板推送失败，未查到店铺信息");
                                } else {
                                    String gzhAppId = store.getGzhAppId();
                                    String gzhAppSecret = store.getGzhAppSecret();
                                    if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                                        log.info("库存不足提醒模板推送失败，店铺未绑定公众号");
                                    } else {
                                        String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                                        String result1 = HttpUtils.sendGet(url1);
                                        JSONObject resultJson1 = JSON.parseObject(result1);
                                        String errcode = resultJson1.getString("errcode");
                                        if (errcode != null && !"0".equals(errcode)) {
                                            log.info("库存不足提醒模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                                        } else {
                                            String accessToken = resultJson1.getString("access_token");
                                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                                            MsgTemplate msgTemplate = msgTemplateListService.getByTitle("库存不足提醒", storeId);
                                            String templateId = msgTemplate.getTemplateId();
                                            util.inventoryInsufficientNotice(templateId, bossGzhOpenId, cm.getTradeName(), String.valueOf(cm.getInventory()), sdf.format(new Date()), xcxAppId, "", accessToken);
                                            log.info("库存不足提醒模板推送成功");
                                        }
                                    }
                                }
                            }
                        }

                    } catch (Exception e) {
                        log.error("库存不足提醒模板推送失败，发生异常", e);
                    }
                }
                commodityManagementService.updateById(cm);

                m.put("pic", cm.getProductPic());
                m.put("detailsUrl", cm.getDetailsUrl());

                // 出库记录明细
                OutStorageDetail outStorageDetail = new OutStorageDetail();
                outStorageDetail.setCommodityId(id);
                outStorageDetail.setCommodityName(cm.getTradeName());
                outStorageDetail.setCommoditySpecs(cm.getSpecification());
                outStorageDetail.setOutQty(count.intValue());
                outStorageDetail.setStoreId(storeId);
                outStorageDetailList.add(outStorageDetail);

                // 出入库明细
                StorageOutinDetail storageOutinDetail = new StorageOutinDetail();
                storageOutinDetail.setCommodityName(cm.getTradeName());
                storageOutinDetail.setCommodityId(cm.getId());
                storageOutinDetail.setOperateType("出库操作");
                storageOutinDetail.setOutinQty(count.intValue());
                storageOutinDetail.setRemainQty(cm.getInventory());
                storageOutinDetail.setBillTime(new Date());
                storageOutinDetail.setOperator(sysUser.getRealname());
                storageOutinDetail.setStoreId(storeId);
                storageOutinDetailList.add(storageOutinDetail);

                BaseOrderCommodity boc = new BaseOrderCommodity();
                boc.setOrderId(order.getId());
                boc.setCommodityId(id);
                boc.setCommodityName(name);
                boc.setCommoditySpecs(specification);
                boc.setCommodityQty(countStr);
                boc.setUnitPrice(price);
                boc.setTotalPrice(totalPrice);
                boc.setPreferAmount(discountAmount);
                boc.setGiveFlag(free);
                boc.setPic(pic);
                boc.setStoreId(storeId);
                boc.setCommodityJsonStr(JSON.toJSONString(cm));
                if (xiaoshouStaff != null) {
// 修改计算方式
                    // 员工提成
                    boc.setCommissionOwner(xiaoshouStaff.getId());
                    boc.setCommissionOwnerName(xiaoshouStaff.getName());
//                    BigDecimal rewardRate;
//                    BaseStaffStatusSpecial bsss = baseStaffStatusSpecialService.getOne(new QueryWrapper<BaseStaffStatusSpecial>()
//                            .eq("staff_status_id", xiaoshouStaff.getEmployeeId())
//                            .eq("type", "1")
//                            .eq("shop_id", id));
//                    if (bsss != null) {
//                        rewardRate = new BigDecimal(String.valueOf(bsss.getRewardRate()));
//                    } else {
//                        BaseStaffStatus bss = baseStaffStatusService.getById(xiaoshouStaff.getEmployeeId());
//                        rewardRate = new BigDecimal(String.valueOf(bss.getShopReward()));
//                    }
                    //BigDecimal commissionMoney = realTotalPrice.multiply(rewardRate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    boc.setCommissionMoney(saleTC.doubleValue());
                    commissionMoneyAll = commissionMoneyAll.add(saleTC);

                    // 销售提成
//                    BigDecimal sellMoney = new BigDecimal(String.valueOf(xiaoshouStaff.getSellMoney()));
//                    xiaoshouStaff.setSellMoney(sellMoney.add(commissionMoney).doubleValue());
                    // 累计提成
                    BigDecimal totalDeduction = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalDeduction()));
                    xiaoshouStaff.setTotalDeduction(totalDeduction.add(saleTC).doubleValue());
                    // 总业绩
                    BigDecimal totalSall = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSell()));
                    xiaoshouStaff.setTotalSell(totalSall.add(realTotalPrice).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSalary()));
                    xiaoshouStaff.setTotalSalary(totalSalary.add(saleTC).doubleValue());
                    staffManagementService.updateById(xiaoshouStaff);
                    m.put("staffId", xiaoshouStaff.getId());
                    m.put("staffName", xiaoshouStaff.getName());
                    m.put("staffCommission", saleTC);
                }
                if (dividendStock != null) {
                    // 股东分红
                    boc.setDividendOwner(dividendStock.getId());
                    boc.setDividendOwnerName(dividendStock.getStockName());

                    // 价格 * 最低利率限额 = 老板最低获利
                    BigDecimal commodityMinimumMargin = new BigDecimal(String.valueOf(cm.getMinimumMargin()));
                    BigDecimal lowPrice = totalPriceDecimal.multiply(commodityMinimumMargin).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 实际售价 * 毛利率 * 股东分红比例 = 股东分红
                    BigDecimal commodityGrossRate = new BigDecimal(String.valueOf(cm.getGrossRate()));
                    BigDecimal stockProrateDividends = new BigDecimal(String.valueOf(dividendStock.getProrateDividends()));
                    BigDecimal dividendMoney = realTotalPrice.multiply(commodityGrossRate).multiply(stockProrateDividends).divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP);
                    // (实际售价 - 股东分红) 应大于 老板最低获利，否则不给股东分红
                    if (lowPrice.compareTo(realTotalPrice.subtract(dividendMoney)) >= 0) {
                        dividendMoney = BigDecimal.ZERO;
                    }
                    boc.setDividendMoney(dividendMoney.doubleValue());
                    dividendMoneyAll = dividendMoneyAll.add(dividendMoney);

                    // 总分红
                    BigDecimal totalDividend = new BigDecimal(String.valueOf(dividendStock.getTotalDividend()));
                    dividendStock.setTotalDividend(totalDividend.add(dividendMoney).doubleValue());
                    // 可提现分红
                    BigDecimal canWithdrawal = new BigDecimal(String.valueOf(dividendStock.getCanWithdrawal()));
                    dividendStock.setCanWithdrawal(canWithdrawal.add(dividendMoney).doubleValue());
                    // 带动营业额
                    BigDecimal driveTurnover = new BigDecimal(String.valueOf(dividendStock.getDriveTurnover()));
                    dividendStock.setDriveTurnover(driveTurnover.add(realTotalPrice).doubleValue());
                    driveTurnoverAll = driveTurnoverAll.add(realTotalPrice);
                    stockManageService.updateById(dividendStock);

                    // 会员带动分红
                    BigDecimal shareholderDividends = new BigDecimal(String.valueOf(mm.getShareholderDividends()));
                    mm.setShareholderDividends(shareholderDividends.add(dividendMoney).doubleValue());
                    memberManagementService.updateById(mm);
                }
                baseOrderCommodityService.save(boc);
            } else {
                // ------------------------- 项目 -------------------------
                ProjectManagement pm = projectManagementService.getById(id);
                if (pm == null) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return Result.error("选择了不存在的项目");
                }

                m.put("pic", pm.getProjectPic());
                m.put("detailsUrl", pm.getDetailsUrl());

                BigDecimal singleTotalPriceDecimal = totalPriceDecimal.divide(count, 2, RoundingMode.HALF_UP);
                BigDecimal singleDiscountAmountDecimal = discountAmountDecimal.divide(count, 2, RoundingMode.HALF_UP);
                BigDecimal singleRealTotalPrice = realTotalPrice.divide(count, 2, RoundingMode.HALF_UP);

                // 数量为几，就插入几条
                for (int i = 0; i < count.intValue(); i++) {
                    BaseOrderProject bop = new BaseOrderProject();
                    bop.setOrderId(order.getId());
                    bop.setProjectId(id);
                    bop.setProjectName(name);
                    bop.setProjectQty("1");
                    bop.setUnitPrice(price);
                    bop.setTotalPrice(String.valueOf(singleTotalPriceDecimal));
                    bop.setPreferAmount(String.valueOf(singleDiscountAmountDecimal));
                    bop.setGiveFlag(free);
                    bop.setPic(pic);
                    bop.setStoreId(storeId);
                    bop.setProjectJsonStr(JSON.toJSONString(pm));
                    if (xiaoshouStaff != null) {
                        // 员工提成
                        bop.setCommissionOwner(xiaoshouStaff.getId());
                        bop.setCommissionOwnerName(xiaoshouStaff.getName());
//                        BigDecimal rewardRate;
//                        BaseStaffStatusSpecial bsss = baseStaffStatusSpecialService.getOne(new QueryWrapper<BaseStaffStatusSpecial>()
//                                .eq("staff_status_id", xiaoshouStaff.getEmployeeId())
//                                .eq("type", "2")
//                                .eq("shop_id", id));
//                        if (bsss != null) {
//
//                            rewardRate = new BigDecimal(String.valueOf(bsss.getRewardRate()));
//                        } else {
//
//                            BaseStaffStatus bss = baseStaffStatusService.getById(xiaoshouStaff.getEmployeeId());
//                            rewardRate = new BigDecimal(String.valueOf(bss.getProjectReward()));
//                        }
//                        BigDecimal commissionMoney = singleRealTotalPrice.multiply(rewardRate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                        bop.setCommissionMoney(saleTC.doubleValue());
                        commissionMoneyAll = commissionMoneyAll.add(saleTC);

                        // 销售提成
//                        BigDecimal sellMoney = new BigDecimal(String.valueOf(xiaoshouStaff.getSellMoney()));
//                        xiaoshouStaff.setSellMoney(sellMoney.add(saleTC).doubleValue());
                        // 累计提成
                        BigDecimal totalDeduction = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalDeduction()));
                        xiaoshouStaff.setTotalDeduction(totalDeduction.add(saleTC).doubleValue());
                        // 总业绩
                        BigDecimal totalSall = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSell()));
                        xiaoshouStaff.setTotalSell(totalSall.add(singleRealTotalPrice).doubleValue());
                        // 总薪资
                        BigDecimal totalSalary = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSalary()));
                        xiaoshouStaff.setTotalSalary(totalSalary.add(saleTC).doubleValue());
                        staffManagementService.updateById(xiaoshouStaff);
                        m.put("staffId", xiaoshouStaff.getId());
                        m.put("staffName", xiaoshouStaff.getName());
                        BigDecimal staffCommission = m.get("staffCommission") == null ? BigDecimal.ZERO : new BigDecimal(String.valueOf(m.get("staffCommission")));
                        m.put("staffCommission", staffCommission.add(saleTC));
                    }
                    if (dividendStock != null) {
                        // 股东分红
                        bop.setDividendOwner(dividendStock.getId());
                        bop.setDividendOwnerName(dividendStock.getStockName());

                        // 价格 * 最低利率限额 = 老板最低获利
                        BigDecimal commodityMinimumMargin = new BigDecimal(String.valueOf(pm.getMinimumProfit()));
                        BigDecimal lowPrice = singleTotalPriceDecimal.multiply(commodityMinimumMargin).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                        // 实际售价 * 毛利率 * 股东分红比例 = 股东分红
                        BigDecimal commodityGrossRate = new BigDecimal(String.valueOf(pm.getGrossProfit()));
                        BigDecimal stockProrateDividends = new BigDecimal(String.valueOf(dividendStock.getProrateDividends()));
                        BigDecimal dividendMoney = singleRealTotalPrice.multiply(commodityGrossRate).multiply(stockProrateDividends).divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP);
                        // (实际售价 - 股东分红) 应大于 老板最低获利，否则不给股东分红
                        if (lowPrice.compareTo(singleRealTotalPrice.subtract(dividendMoney)) >= 0) {
                            dividendMoney = BigDecimal.ZERO;
                        }
                        bop.setDividendMoney(dividendMoney.doubleValue());
                        dividendMoneyAll = dividendMoneyAll.add(dividendMoney);

                        // 总分红
                        BigDecimal totalDividend = new BigDecimal(String.valueOf(dividendStock.getTotalDividend()));
                        dividendStock.setTotalDividend(totalDividend.add(dividendMoney).doubleValue());
                        // 可提现分红
                        BigDecimal canWithdrawal = new BigDecimal(String.valueOf(dividendStock.getCanWithdrawal()));
                        dividendStock.setCanWithdrawal(canWithdrawal.add(dividendMoney).doubleValue());
                        // 带动营业额
                        BigDecimal driveTurnover = new BigDecimal(String.valueOf(dividendStock.getDriveTurnover()));
                        dividendStock.setDriveTurnover(driveTurnover.add(singleRealTotalPrice).doubleValue());
                        driveTurnoverAll = driveTurnoverAll.add(singleRealTotalPrice);
                        stockManageService.updateById(dividendStock);

                        // 会员带动分红
                        BigDecimal shareholderDividends = new BigDecimal(String.valueOf(mm.getShareholderDividends()));
                        mm.setShareholderDividends(shareholderDividends.add(dividendMoney).doubleValue());
                        memberManagementService.updateById(mm);
                        giveHighStock(dividendStock.getStoreId(), dividendStock.getId(), realTotalPrice);
                    }
                    String projectId = bop.getProjectId();
                    if (projectId != null && bop.getIndate() == null) {
                        ProjectManagement project = projectManagementService.getById(projectId);
                        if (project != null) {

                            bop.setIndate(project.getIndate());
                            bop.setTimingWay(project.getTimingWay());
                            if (bop.getValidateTime() == null && "1".equals(project.getTimingWay())) {
                                LocalDate l = LocalDate.now();
                                l=l.plusDays(Integer.parseInt(project.getIndate()));
                                bop.setValidateTime(DateUtils.local2util(l));
                            }

                        }
                    }
                    bop.setIsValid("1");
                    baseOrderProjectService.save(bop);

                    // 项目关联的商品：一个商品一条记录
                    List<Map<String, Object>> shopList = cashierService.listProjectShop(id);
                    shopList.forEach(map1 -> {
                        if (map1 == null) {
                            return;
                        }
                        String countCommodityStr = map1.get("count") == null ? "0" : String.valueOf(map1.get("count"));
                        BigDecimal countCommodity = new BigDecimal(countCommodityStr);
                        String tradeName = map1.get("trade_name") == null ? null : String.valueOf(map1.get("trade_name"));

                        BaseOrderCommodityWriteoff bocw = new BaseOrderCommodityWriteoff();
                        bocw.setOrderId(order.getId());
                        bocw.setOrderProjectId(bop.getId());
                        bocw.setCommodityName(tradeName);
                        bocw.setTotalQty(countCommodity.intValue());
                        bocw.setRemainQty(countCommodity.intValue());
                        bocw.setWriteoffQty(0);
                        bocw.setStatus(0);
                        bocw.setStoreId(storeId);
                        baseOrderCommodityWriteoffService.save(bocw);
                    });

                    // 项目关联的服务：有多少次服务，就插入多少条记录
                    List<Map<String, Object>> serveList = cashierService.listProjectServe(id);
                    serveList.forEach(map1 -> {
                        if (map1 == null) {
                            return;
                        }
                        String countServeStr = map1.get("count") == null ? "0" : String.valueOf(map1.get("count"));
                        BigDecimal countServe = new BigDecimal(countServeStr);
                        String serveName = map1.get("serve_name") == null ? null : String.valueOf(map1.get("serve_name"));
                        String serveId = map1.get("id") == null ? null : String.valueOf(map1.get("id"));

                        BaseOrderServiceWriteoff bosw = new BaseOrderServiceWriteoff();
                        bosw.setOrderId(order.getId());
                        bosw.setOrderProjectId(bop.getId());
                        bosw.setServiceId(serveId);
                        bosw.setServiceName(serveName);
                        bosw.setStatus(0);
                        bosw.setStoreId(storeId);
//                  // 服务次数 = 项目数量 * 项目包含服务次数
//                  int i = countServe.multiply(count).intValue();
                        for (int j = 0; j < countServe.intValue(); j++) {
                            baseOrderServiceWriteoffService.save(bosw);
                            bosw.setId(null);
                        }
                    });
                }
            }
        }
        order.setCommodityListJsonStr(JSON.toJSONString(commodityList));
        order.setCouponListJsonStr(JSON.toJSONString(couponList));

        if (outStorageDetailList.size() > 0) {
            OutStorageMain outStorageMain = new OutStorageMain();
            String billNo = ToolsUtils.getBillNo("OS");
            outStorageMain.setBillNo(billNo);
            outStorageMain.setOutType("01");
            outStorageMain.setBillTime(new Date());
            outStorageMain.setPreparer(sysUser.getRealname());
            outStorageMain.setStoreId(storeId);
            outStorageMainService.save(outStorageMain);
            for (OutStorageDetail outStorageDetail : outStorageDetailList) {
                outStorageDetail.setMainId(outStorageMain.getId());
                outStorageDetail.setBillNo(billNo);
                outStorageDetail.setOutinType("01");
                outStorageDetailService.save(outStorageDetail);
            }
            for (StorageOutinDetail storageOutinDetail : storageOutinDetailList) {
                storageOutinDetail.setBillNo(billNo);
                storageOutinDetail.setOutinType("01");
                storageOutinDetailService.save(storageOutinDetail);
            }
        }
        BigDecimal staffShareMoney = BigDecimal.ZERO;

        // 股东管家分红
        if (StringUtils.isNotEmpty(mm.getMyStockId())) {
            // 消费者是股东
            StockManage stockMe = stockManageService.getById(mm.getMyStockId());
            if (stockMe != null) {
                // 查出拿分红的员工
                StaffManagement dividendStaff = staffManagementService.getById(stockMe.getShareholdersHousekeeperId());
                if (dividendStaff != null) {
                    BigDecimal ratio = new BigDecimal(String.valueOf(stockMe.getShareholdersRatio()));
                    staffShareMoney = realAmountDecimal.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 分红
                    BigDecimal totalShare = new BigDecimal(String.valueOf(dividendStaff.getTotalShare()));
                    dividendStaff.setTotalShare(totalShare.add(staffShareMoney).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(dividendStaff.getTotalSalary()));
                    dividendStaff.setTotalSalary(totalSalary.add(staffShareMoney).doubleValue());
                    staffManagementService.updateById(dividendStaff);
                    order.setStaffShareId(dividendStaff.getId());
                    order.setStaffShareName(dividendStaff.getName());
                    order.setStaffShareType("股东");
                }
            }
        } else {
            // 消费者不是股东
            StockManage stockUp = stockManageService.getById(mm.getStockId());
            if (stockUp != null) {
                // 查出拿分红的员工
                StaffManagement dividendStaff = staffManagementService.getById(stockUp.getShareholdersHousekeeperId());
                if (dividendStaff != null) {
                    BigDecimal ratio = new BigDecimal(String.valueOf(stockUp.getMemberRatio()));
                    staffShareMoney = realAmountDecimal.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 分红
                    BigDecimal totalShare = new BigDecimal(String.valueOf(dividendStaff.getTotalShare()));
                    dividendStaff.setTotalShare(totalShare.add(staffShareMoney).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(dividendStaff.getTotalSalary()));
                    dividendStaff.setTotalSalary(totalSalary.add(staffShareMoney).doubleValue());
                    staffManagementService.updateById(dividendStaff);
                    order.setStaffShareId(dividendStaff.getId());
                    order.setStaffShareName(dividendStaff.getName());
                    order.setStaffShareType("会员");
                }
            }
        }
        order.setStaffPercentage(commissionMoneyAll.doubleValue());
        order.setStockPercentage(dividendMoneyAll.doubleValue());
        order.setDriveTurnoverAll(driveTurnoverAll.doubleValue());
        order.setStaffShareMoney(staffShareMoney.doubleValue());
        baseOrderService.updateById(order);

        // 会员消费次数
        mm.setConsumption(mm.getConsumption() + 1);
        // 会员消费总额
        BigDecimal expendamount = new BigDecimal(String.valueOf(mm.getExpendamount()));
        mm.setExpendamount(expendamount.add(realAmountDecimal).doubleValue());
        if ("1".equals(mm.getStatus())) {
            // 股东会员消费总额
            BigDecimal stockMemberExpendamount = new BigDecimal(String.valueOf(mm.getStockMemberExpendamount()));
            mm.setStockMemberExpendamount(stockMemberExpendamount.add(realAmountDecimal).doubleValue());
        }
        memberManagementService.updateById(mm);

        // 模板消息
        try {
            String gzhOpenId = mm.getGzhOpenId();
            String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
            if (gzhOpenId == null) {
                log.info("发送消费提醒模板推送失败，会员未绑定公众号");
            } else {
                StoreInfo store = storeInfoService.getById(storeId);
                if (store == null) {
                    log.info("发送消费提醒模板推送失败，未查到店铺信息");
                } else {
                    String gzhAppId = store.getGzhAppId();
                    String gzhAppSecret = store.getGzhAppSecret();
                    if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                        log.info("发送消费提醒模板推送失败，店铺未绑定公众号");
                    } else {
                        String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                        String result1 = HttpUtils.sendGet(url1);
                        JSONObject resultJson1 = JSON.parseObject(result1);
                        String errcode = resultJson1.getString("errcode");
                        if (errcode != null && !"0".equals(errcode)) {
                            log.info("发送消费提醒模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                        } else {
                            String accessToken = resultJson1.getString("access_token");
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                            MsgTemplate msgTemplate = msgTemplateListService.getByTitle("消费提醒", storeId);
                            String templateId = msgTemplate.getTemplateId();
                            BaseOrder baseOrder = baseOrderService.getById(order.getId());
                            Integer consumeNoticeFlag = 0;
                            if (baseOrder != null) {
                                consumeNoticeFlag = baseOrder.getConsumeNoticeFlag();
                            }
                            if (consumeNoticeFlag != 1) {
                                util.consumeNotice(templateId, gzhOpenId, sdf.format(new Date()), String.valueOf(order.getRealAmount()), order.getStoreName(), store.getXcxAppId(), "user/order/index?type=0", accessToken);
                                baseOrderService.updateConsumeNoticeFlag(1, order.getId());
                                log.info("发送消费提醒模板推送成功");
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("发送消费提醒模板推送失败，发生异常", e);
        }

        if (dividendStock != null && dividendMoneyAll.compareTo(BigDecimal.ZERO) > 0) {
            // 模板消息
            try {
                MemberManagement mm1 = memberManagementService.getById(dividendStock.getMemberId());
                String gzhOpenId = mm1.getGzhOpenId();
                if (gzhOpenId == null) {
                    log.info("发送分红提醒模板推送失败，会员未绑定公众号");
                } else {
                    StoreInfo store = storeInfoService.getById(storeId);
                    if (store == null) {
                        log.info("发送分红提醒模板推送失败，未查到店铺信息");
                    } else {
                        String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
                        String gzhAppId = store.getGzhAppId();
                        String gzhAppSecret = store.getGzhAppSecret();
                        if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                            log.info("发送分红提醒模板推送失败，店铺未绑定公众号");
                        } else {
                            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                            String result1 = HttpUtils.sendGet(url1);
                            JSONObject resultJson1 = JSON.parseObject(result1);
                            String errcode = resultJson1.getString("errcode");
                            if (errcode != null && !"0".equals(errcode)) {
                                log.info("发送分红提醒模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                            } else {
                                String accessToken = resultJson1.getString("access_token");
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                                MsgTemplate msgTemplate = msgTemplateListService.getByTitle("订单分红提醒", storeId);
                                String templateId = msgTemplate.getTemplateId();
                                util.orderDividendNotice(templateId, gzhOpenId, String.valueOf(dividendMoneyAll), String.valueOf(dividendStock.getTotalDividend()), sdf.format(new Date()), store.getXcxAppId(), "user/share/bonus", accessToken);

                                log.info("发送分红提醒模板推送成功");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("发送分红提醒模板推送失败，发生异常", e);
            }
        }

        String strCommodity = order.getCommodityListJsonStr();
        JSONArray objects = JSONObject.parseArray(strCommodity);
        List<Map<String, Object>> auditListMap = (List<Map<String, Object>>) ToolsUtils.translate(objects);
        if (auditListMap != null) {
            for (int j = 0; j < auditListMap.size(); j++) {
                String staffId = "";
                if (auditListMap.get(j).get("staffId") != null) {
                    staffId = auditListMap.get(j).get("staffId").toString();
                }
                if (staffId != "") {
                    BaseOrderCommodityJson commdoityJson = new BaseOrderCommodityJson();
                    commdoityJson.setId(UUID.randomUUID().toString());
                    commdoityJson.setOrderCode(order.getOrderCode());
                    commdoityJson.setName(auditListMap.get(j).get("name").toString());
                    commdoityJson.setSpecification(auditListMap.get(j).get("specification").toString());
                    commdoityJson.setCount(Integer.parseInt(auditListMap.get(j).get("count").toString()));
                    commdoityJson.setPrice(Double.parseDouble(auditListMap.get(j).get("price").toString()));
                    commdoityJson.setTotalPrice(Double.parseDouble(auditListMap.get(j).get("totalPrice").toString()));
                    commdoityJson.setDiscountAmount(Double.parseDouble(auditListMap.get(j).get("discountAmount").toString()));
                    commdoityJson.setFree(false);
                    if (auditListMap.get(j).get("staffPercentage") !=null){
                        commdoityJson.setStaffPercentage(String.valueOf(auditListMap.get(j).get("staffPercentage")));
                    }
                    commdoityJson.setStaffId(auditListMap.get(j).get("staffId").toString());
                    //commdoityJson.setStaffName(auditListMap.get(j).get("staffName").toString());
                    commdoityJson.setType(Integer.parseInt(auditListMap.get(j).get("type").toString()));
                    try {
                        commdoityJson.setStaffCommission(Double.parseDouble(auditListMap.get(j).get("staffCommission").toString()));
                    } catch (Exception ex) {
                        commdoityJson.setStaffCommission(0.0);
                    }

                    baseOrderService.addCommodityJson(commdoityJson);
                }
            }
        }
        MemberEnterStoreRecord memberEnterStoreRecord = new MemberEnterStoreRecord();
        memberEnterStoreRecord.setId(null);
        memberEnterStoreRecord.setStoreId(storeId);
        memberEnterStoreRecord.setMemberId(memberId);
        memberEnterStoreRecord.setEnterStoreDate(new Date());
        memberEnterStoreRecordService.save(memberEnterStoreRecord);
        return Result.OK(order.getId());
    }

    /**
     * 退单
     * 参数：*orderId
     */
    @PostMapping("/returnOrder")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> returnOrder(@RequestBody Map<String, Object> map1, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map1.put("storeId", storeId);
        String orderId = map1.get("orderId") == null ? null : String.valueOf(map1.get("orderId"));
        if (StringUtils.isEmpty(orderId)) {
            return Result.error("参数不全");
        }

        BaseOrder order = baseOrderService.getById(orderId);
        if (order == null) {
            return Result.error("未找到对应的订单");
        }

        // 退单条件判断
        if (!"1".equals(order.getOrderStatus())) {
            return Result.error("订单未在已付款状态，无法退单");
        }
        List<BaseOrderCommodityWriteoff> bocwList = baseOrderCommodityWriteoffService.list(new QueryWrapper<BaseOrderCommodityWriteoff>().eq("order_id", orderId));
        List<BaseOrderServiceWriteoff> boswList = baseOrderServiceWriteoffService.list(new QueryWrapper<BaseOrderServiceWriteoff>().eq("order_id", orderId));
        long countUsedBocw = bocwList.stream().filter(bocw -> bocw.getWriteoffQty() > 0).count();
        long countUsedBosw = boswList.stream().filter(bosw -> bosw.getStatus() == 1).count();
        if (countUsedBocw > 0 || countUsedBosw > 0) {
            return Result.error("订单中商品或服务已进行过核销，无法退单");
        }

        // 退单逻辑
        Map<String, Object> map = (Map<String, Object>) JSON.parse(order.getOrderJsonStr());
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
//      String payType = map.get("payType") == null ? null : String.valueOf(map.get("payType"));
        String payType = order.getPayType();
        String totalAmount = map.get("totalAmount") == null ? null : String.valueOf(map.get("totalAmount"));
        String totalDiscountAmount = map.get("totalDiscountAmount") == null ? null : String.valueOf(map.get("totalDiscountAmount"));
        String realAmount = map.get("realAmount") == null ? null : String.valueOf(map.get("realAmount"));
        List<Map<String, Object>> commodityList = (List<Map<String, Object>>) map.get("commodityList");
        String useMemberDiscountStr = map.get("useMemberDiscount") == null ? null : String.valueOf(map.get("useMemberDiscount"));
        String memberDiscountStr = map.get("memberDiscount") == null ? null : String.valueOf(map.get("memberDiscount"));
        List<Map<String, Object>> couponList = map.get("couponList") == null ? new ArrayList<>() : (List<Map<String, Object>>) map.get("couponList");
        String remark = map.get("remark") == null ? null : String.valueOf(map.get("remark"));
        String preOrderId = map.get("preOrderId") == null ? null : String.valueOf(map.get("preOrderId"));
        BigDecimal realAmountDecimal = new BigDecimal(realAmount);
        String balanceAmountStr = map.get("balanceAmount") == null ? "0" : String.valueOf(map.get("balanceAmount"));
        BigDecimal balanceAmount = new BigDecimal(balanceAmountStr);
        String stockBalanceAmountStr = map.get("stockBalanceAmount") == null ? "0" : String.valueOf(map.get("stockBalanceAmount"));
        BigDecimal stockBalanceAmount = new BigDecimal(stockBalanceAmountStr);
        boolean useMemberDiscount = "1".equals(useMemberDiscountStr);
        BigDecimal memberDiscount = memberDiscountStr == null ? BigDecimal.TEN : new BigDecimal(memberDiscountStr);
        String reductionStr = map.get("reduction") == null ? "0" : String.valueOf(map.get("reduction"));
        BigDecimal reduction = new BigDecimal(reductionStr);
        String outTradeNo = map.get("outTradeNo") == null ? null : String.valueOf(map.get("outTradeNo"));

        MemberManagement mm = memberManagementService.getById(memberId);

        // 参与分红的股东
        StockManage dividendStock = null;

        if ("1".equals(mm.getStatus())) {
            dividendStock = stockManageService.getById(mm.getStockId());
            if (dividendStock != null) {
                MemberManagement dividendStockMember = memberManagementService.getOne(new QueryWrapper<MemberManagement>().eq("my_stock_id", dividendStock.getId()));
            }
        }
        switch (payType) {
            case "微信支付":
                break;
            case "扫码支付":
            case "现金支付":
            case "支付宝记账":
            case "微信记账":
                if (balanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                    mm.setBalance(balance.add(balanceAmount).doubleValue());
                    memberManagementService.updateById(mm);
                }
                if (stockBalanceAmount.compareTo(BigDecimal.ZERO) > 0) {
                    StockManage sm = stockManageService.getById(mm.getMyStockId());
                    BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                    sm.setEquityBalance(equityBalance.add(stockBalanceAmount).doubleValue());
                    stockManageService.updateById(sm);
                }
                break;
            case "会员余额支付":
                BigDecimal balance = new BigDecimal(String.valueOf(mm.getBalance()));
                mm.setBalance(balance.add(realAmountDecimal).doubleValue());
                memberManagementService.updateById(mm);
                break;
            case "股本余额支付":
                StockManage sm = stockManageService.getById(mm.getMyStockId());
                BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
                sm.setEquityBalance(equityBalance.add(realAmountDecimal).doubleValue());
                stockManageService.updateById(sm);
                break;
        }

        for (Map<String, Object> m : couponList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String numStr = m.get("num") == null ? "0" : String.valueOf(m.get("num"));
            int num = Integer.parseInt(numStr);
            BaseMemberVipCoupon bmvc = baseMemberVipCouponService.getById(id);
            bmvc.setNum(bmvc.getNum() + num);
            baseMemberVipCouponService.updateById(bmvc);

            // 这两个不退回
//         // 处理优惠劵使用情况、发卡记录到店情况
//         BaseMemberVip bmv = baseMemberVipService.getById(bmvc.getMemberVipId());
//         bmv.setUsed("0");
//         baseMemberVipService.updateById(bmv);
//         IssuingRecords ir = issuingRecordsService.getById(bmv.getIssuingRecordsId());
//         if (ir != null && ir.getToStoreNum() > 0) {
//            ir.setToStoreNum(ir.getToStoreNum() - 1);
//            issuingRecordsService.updateById(ir);
//         }
        }
        // 订单总员工销售提成
        BigDecimal commissionMoneyAll = BigDecimal.ZERO;
        // 订单总股东分红
        BigDecimal dividendMoneyAll = BigDecimal.ZERO;
        // 订单总带动营业额
        BigDecimal driveTurnoverAll = BigDecimal.ZERO;

//      // 出库记录明细
//      List<OutStorageDetail> outStorageDetailList = new ArrayList<>();
        // 入库记录明细
        List<InStorageDetail> inStorageDetailList = new ArrayList<>();
        // 出入库明细
        List<StorageOutinDetail> storageOutinDetailList = new ArrayList<>();

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        for (Map<String, Object> m : commodityList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String type = m.get("type") == null ? null : String.valueOf(m.get("type"));
            String countStr = m.get("count") == null ? "0" : String.valueOf(m.get("count"));
            BigDecimal count = new BigDecimal(countStr);
            String name = m.get("name") == null ? "0" : String.valueOf(m.get("name"));
            String specification = m.get("specification") == null ? "0" : String.valueOf(m.get("specification"));
            String price = m.get("price") == null ? "0" : String.valueOf(m.get("price"));
            String totalPrice = m.get("totalPrice") == null ? "0" : String.valueOf(m.get("totalPrice"));
            String discountAmount = m.get("discountAmount") == null ? "0" : String.valueOf(m.get("discountAmount"));
            String free = m.get("free") == null ? "0" : String.valueOf(m.get("free"));
            String pic = m.get("pic") == null ? "0" : String.valueOf(m.get("pic"));
            String staffId = m.get("staffId") == null ? "0" : String.valueOf(m.get("staffId"));

            BigDecimal totalPriceDecimal = new BigDecimal(totalPrice);
            BigDecimal discountAmountDecimal = new BigDecimal(discountAmount);
            BigDecimal realTotalPrice = totalPriceDecimal.subtract(discountAmountDecimal);

            // 拿销售提成的员工
            StaffManagement xiaoshouStaff = staffManagementService.getById(staffId);

            if ("1".equals(type)) {
                // ------------------------- 商品 -------------------------

                CommodityManagement cm = commodityManagementService.getById(id);
                if (cm != null) {
                    cm.setInventory(cm.getInventory() + count.intValue());
                    commodityManagementService.updateById(cm);

                    // 入库记录明细
                    InStorageDetail inStorageDetail = new InStorageDetail();
                    inStorageDetail.setCommodityId(id);
                    inStorageDetail.setCommodityName(cm.getTradeName());
                    inStorageDetail.setCommoditySpecs(cm.getSpecification());
                    inStorageDetail.setInQty(count.intValue());
                    inStorageDetail.setStoreId(storeId);
                    inStorageDetailList.add(inStorageDetail);

                    // 出入库明细
                    StorageOutinDetail storageOutinDetail = new StorageOutinDetail();
                    storageOutinDetail.setCommodityName(cm.getTradeName());
                    storageOutinDetail.setCommodityId(cm.getId());
                    storageOutinDetail.setOperateType("入库操作");
                    storageOutinDetail.setOutinQty(count.intValue());
                    storageOutinDetail.setRemainQty(cm.getInventory());
                    storageOutinDetail.setBillTime(new Date());
                    storageOutinDetail.setOperator(sysUser.getRealname());
                    storageOutinDetail.setStoreId(storeId);
                    storageOutinDetailList.add(storageOutinDetail);
                }

                BaseOrderCommodity boc = new BaseOrderCommodity();
                boc.setOrderId(order.getId());
                boc.setCommodityId(id);
                boc.setCommodityName(name);
                boc.setCommoditySpecs(specification);
                boc.setCommodityQty(countStr);
                boc.setUnitPrice(price);
                boc.setTotalPrice(totalPrice);
                boc.setPreferAmount(discountAmount);
                boc.setGiveFlag(free);
                boc.setPic(pic);
                boc.setStoreId(storeId);
                boc.setCommodityJsonStr(JSON.toJSONString(cm));
                if (xiaoshouStaff != null) {
                    // 员工提成
                    boc.setCommissionOwner(staffId);
                    boc.setCommissionOwnerName(xiaoshouStaff.getName());
                    BigDecimal rewardRate;
                    BaseStaffStatusSpecial bsss = baseStaffStatusSpecialService.getOne(new QueryWrapper<BaseStaffStatusSpecial>()
                            .eq("staff_status_id", xiaoshouStaff.getEmployeeId())
                            .eq("type", "1")
                            .eq("shop_id", id));
                    if (bsss != null) {
                        rewardRate = new BigDecimal(String.valueOf(bsss.getRewardRate()));
                    } else {
                        BaseStaffStatus bss = baseStaffStatusService.getById(xiaoshouStaff.getEmployeeId());
                        rewardRate = new BigDecimal(String.valueOf(bss.getShopReward()));
                    }
                    BigDecimal commissionMoney = realTotalPrice.multiply(rewardRate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    boc.setCommissionMoney(commissionMoney.doubleValue());
                    commissionMoneyAll = commissionMoneyAll.add(commissionMoney);

                    // 销售提成
                    BigDecimal sellMoney = new BigDecimal(String.valueOf(xiaoshouStaff.getSellMoney()));
                    xiaoshouStaff.setSellMoney(sellMoney.subtract(commissionMoney).doubleValue());
                    // 累计提成
                    BigDecimal totalDeduction = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalDeduction()));
                    xiaoshouStaff.setTotalDeduction(totalDeduction.subtract(commissionMoney).doubleValue());
                    // 总业绩
                    BigDecimal totalSall = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSell()));
                    xiaoshouStaff.setTotalSell(totalSall.subtract(realTotalPrice).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSalary()));
                    xiaoshouStaff.setTotalSalary(totalSalary.subtract(commissionMoney).doubleValue());
                    staffManagementService.updateById(xiaoshouStaff);
                    m.put("staffId", xiaoshouStaff.getId());
                    m.put("staffName", xiaoshouStaff.getName());
                    m.put("staffCommission", commissionMoney);
                }
                if (dividendStock != null) {
                    // 股东分红
                    boc.setDividendOwner(dividendStock.getId());
                    boc.setDividendOwnerName(dividendStock.getStockName());

                    // 价格 * 最低利率限额 = 老板最低获利
                    BigDecimal commodityMinimumMargin = new BigDecimal(String.valueOf(cm.getMinimumMargin()));
                    BigDecimal lowPrice = totalPriceDecimal.multiply(commodityMinimumMargin).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 实际售价 * 毛利率 * 股东分红比例 = 股东分红
                    BigDecimal commodityGrossRate = new BigDecimal(String.valueOf(cm.getGrossRate()));
                    BigDecimal stockProrateDividends = new BigDecimal(String.valueOf(dividendStock.getProrateDividends()));
                    BigDecimal dividendMoney = realTotalPrice.multiply(commodityGrossRate).multiply(stockProrateDividends).divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP);
                    // (实际售价 - 股东分红) 应大于 老板最低获利，否则不给股东分红
                    if (lowPrice.compareTo(realTotalPrice.subtract(dividendMoney)) >= 0) {
                        dividendMoney = BigDecimal.ZERO;
                    }
                    boc.setDividendMoney(dividendMoney.doubleValue());
                    dividendMoneyAll = dividendMoneyAll.add(dividendMoney);

                    // 总分红
                    BigDecimal totalDividend = new BigDecimal(String.valueOf(dividendStock.getTotalDividend()));
                    dividendStock.setTotalDividend(totalDividend.subtract(dividendMoney).doubleValue());
                    // 可提现分红
                    BigDecimal canWithdrawal = new BigDecimal(String.valueOf(dividendStock.getCanWithdrawal()));
                    dividendStock.setCanWithdrawal(canWithdrawal.subtract(dividendMoney).doubleValue());
                    // 带动营业额
                    BigDecimal driveTurnover = new BigDecimal(String.valueOf(dividendStock.getDriveTurnover()));
                    dividendStock.setDriveTurnover(driveTurnover.subtract(realTotalPrice).doubleValue());
                    driveTurnoverAll = driveTurnoverAll.add(realTotalPrice);
                    stockManageService.updateById(dividendStock);

                    // 会员带动分红
                    BigDecimal shareholderDividends = new BigDecimal(String.valueOf(mm.getShareholderDividends()));
                    mm.setShareholderDividends(shareholderDividends.subtract(dividendMoney).doubleValue());
                    memberManagementService.updateById(mm);
                }
            } else {
                // ------------------------- 项目 -------------------------
                ProjectManagement pm = projectManagementService.getById(id);

                BaseOrderProject bop = new BaseOrderProject();
                bop.setOrderId(order.getId());
                bop.setProjectId(id);
                bop.setProjectName(name);
                bop.setProjectQty(countStr);
                bop.setUnitPrice(price);
                bop.setTotalPrice(totalPrice);
                bop.setPreferAmount(discountAmount);
                bop.setGiveFlag(free);
                bop.setPic(pic);
                bop.setStoreId(storeId);
                bop.setProjectJsonStr(JSON.toJSONString(pm));
                if (xiaoshouStaff != null) {
                    // 员工提成
                    bop.setCommissionOwner(staffId);
                    bop.setCommissionOwnerName(xiaoshouStaff.getName());
                    BigDecimal rewardRate;
                    BaseStaffStatusSpecial bsss = baseStaffStatusSpecialService.getOne(new QueryWrapper<BaseStaffStatusSpecial>()
                            .eq("staff_status_id", xiaoshouStaff.getEmployeeId())
                            .eq("type", "2")
                            .eq("shop_id", id));
                    if (bsss != null) {
                        rewardRate = new BigDecimal(String.valueOf(bsss.getRewardRate()));
                    } else {
                        BaseStaffStatus bss = baseStaffStatusService.getById(xiaoshouStaff.getEmployeeId());
                        rewardRate = new BigDecimal(String.valueOf(bss.getProjectReward()));
                    }
                    BigDecimal commissionMoney = realTotalPrice.multiply(rewardRate).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    bop.setCommissionMoney(commissionMoney.doubleValue());
                    commissionMoneyAll = commissionMoneyAll.add(commissionMoney);

                    // 销售提成
                    BigDecimal sellMoney = new BigDecimal(String.valueOf(xiaoshouStaff.getSellMoney()));
                    xiaoshouStaff.setSellMoney(sellMoney.subtract(commissionMoney).doubleValue());
                    // 累计提成
                    BigDecimal totalDeduction = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalDeduction()));
                    xiaoshouStaff.setTotalDeduction(totalDeduction.subtract(commissionMoney).doubleValue());
                    // 总业绩
                    BigDecimal totalSall = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSell()));
                    xiaoshouStaff.setTotalSell(totalSall.subtract(realTotalPrice).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(xiaoshouStaff.getTotalSalary()));
                    xiaoshouStaff.setTotalSalary(totalSalary.subtract(commissionMoney).doubleValue());
                    staffManagementService.updateById(xiaoshouStaff);
                    m.put("staffId", xiaoshouStaff.getId());
                    m.put("staffName", xiaoshouStaff.getName());
                    m.put("staffCommission", commissionMoney);
                }
                if (dividendStock != null) {
                    // 股东分红
                    bop.setDividendOwner(dividendStock.getId());
                    bop.setDividendOwnerName(dividendStock.getStockName());

                    // 价格 * 最低利率限额 = 老板最低获利
                    BigDecimal commodityMinimumMargin = new BigDecimal(String.valueOf(pm.getMinimumProfit()));
                    BigDecimal lowPrice = totalPriceDecimal.multiply(commodityMinimumMargin).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 实际售价 * 毛利率 * 股东分红比例 = 股东分红
                    BigDecimal commodityGrossRate = new BigDecimal(String.valueOf(pm.getGrossProfit()));
                    BigDecimal stockProrateDividends = new BigDecimal(String.valueOf(dividendStock.getProrateDividends()));
                    BigDecimal dividendMoney = realTotalPrice.multiply(commodityGrossRate).multiply(stockProrateDividends).divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP);
                    // (实际售价 - 股东分红) 应大于 老板最低获利，否则不给股东分红
                    if (lowPrice.compareTo(realTotalPrice.subtract(dividendMoney)) >= 0) {
                        dividendMoney = BigDecimal.ZERO;
                    }
                    bop.setDividendMoney(dividendMoney.doubleValue());
                    dividendMoneyAll = dividendMoneyAll.add(dividendMoney);

                    // 总分红
                    BigDecimal totalDividend = new BigDecimal(String.valueOf(dividendStock.getTotalDividend()));
                    dividendStock.setTotalDividend(totalDividend.subtract(dividendMoney).doubleValue());
                    // 可提现分红
                    BigDecimal canWithdrawal = new BigDecimal(String.valueOf(dividendStock.getCanWithdrawal()));
                    dividendStock.setCanWithdrawal(canWithdrawal.subtract(dividendMoney).doubleValue());
                    // 带动营业额
                    BigDecimal driveTurnover = new BigDecimal(String.valueOf(dividendStock.getDriveTurnover()));
                    dividendStock.setDriveTurnover(driveTurnover.subtract(realTotalPrice).doubleValue());
                    driveTurnoverAll = driveTurnoverAll.add(realTotalPrice);
                    stockManageService.updateById(dividendStock);

                    // 会员带动分红
                    BigDecimal shareholderDividends = new BigDecimal(String.valueOf(mm.getShareholderDividends()));
                    mm.setShareholderDividends(shareholderDividends.subtract(dividendMoney).doubleValue());
                    memberManagementService.updateById(mm);
                }
                String projectId = bop.getProjectId();
                if (projectId != null && bop.getIndate() == null) {
                    ProjectManagement project = projectManagementService.getById(projectId);
                    if (project != null) {

                        bop.setIndate(project.getIndate());
                        bop.setTimingWay(project.getTimingWay());
                        if (bop.getValidateTime() == null && "1".equals(project.getTimingWay())) {
                            LocalDate l = LocalDate.now();
                            l=l.plusDays(Integer.parseInt(project.getIndate()));
                            bop.setValidateTime(DateUtils.local2util(l));
                        }


                    }
                }
                bop.setIsValid("1");
                baseOrderProjectService.save(bop);

            }
        }

        BigDecimal staffShareMoney = BigDecimal.ZERO;

        // 股东管家分红
        if (StringUtils.isNotEmpty(mm.getMyStockId())) {
            // 消费者是股东
            StockManage stockMe = stockManageService.getById(mm.getMyStockId());
            if (stockMe != null) {
                // 查出拿分红的员工
                StaffManagement dividendStaff = staffManagementService.getById(stockMe.getShareholdersHousekeeperId());
                if (dividendStaff != null) {
                    BigDecimal ratio = new BigDecimal(String.valueOf(stockMe.getShareholdersRatio()));
                    staffShareMoney = realAmountDecimal.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 分红
                    BigDecimal totalShare = new BigDecimal(String.valueOf(dividendStaff.getTotalShare()));
                    dividendStaff.setTotalShare(totalShare.subtract(staffShareMoney).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(dividendStaff.getTotalSalary()));
                    dividendStaff.setTotalSalary(totalSalary.subtract(staffShareMoney).doubleValue());
                    staffManagementService.updateById(dividendStaff);
                }
            }
        } else {
            // 消费者不是股东
            StockManage stockUp = stockManageService.getById(mm.getStockId());
            if (stockUp != null) {
                // 查出拿分红的员工
                StaffManagement dividendStaff = staffManagementService.getById(stockUp.getShareholdersHousekeeperId());
                if (dividendStaff != null) {
                    BigDecimal ratio = new BigDecimal(String.valueOf(stockUp.getMemberRatio()));
                    staffShareMoney = realAmountDecimal.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                    // 分红
                    BigDecimal totalShare = new BigDecimal(String.valueOf(dividendStaff.getTotalShare()));
                    dividendStaff.setTotalShare(totalShare.subtract(staffShareMoney).doubleValue());
                    // 总薪资
                    BigDecimal totalSalary = new BigDecimal(String.valueOf(dividendStaff.getTotalSalary()));
                    dividendStaff.setTotalSalary(totalSalary.subtract(staffShareMoney).doubleValue());
                    staffManagementService.updateById(dividendStaff);
                }
            }
        }

        // 更新订单
        order.setOrderStatus("2");
        baseOrderService.updateById(order);

        // 两个待核销删掉
        baseOrderServiceWriteoffService.remove(new QueryWrapper<BaseOrderServiceWriteoff>().eq("order_id", orderId));
        baseOrderCommodityWriteoffService.remove(new QueryWrapper<BaseOrderCommodityWriteoff>().eq("order_id", orderId));

        BaseSelfOrder baseSelfOrder = baseSelfOrderService.getOne(new QueryWrapper<BaseSelfOrder>().eq("order_code", order.getOrderCode()));
        if (baseSelfOrder != null) {
            baseSelfOrder.setOrderStatus("2");
            baseSelfOrderService.updateById(baseSelfOrder);
        }

        // 不处理
//      // 会员消费次数
//      mm.setConsumption(mm.getConsumption() + 1);
        // 会员消费总额
        BigDecimal expendamount = new BigDecimal(String.valueOf(mm.getExpendamount()));
        mm.setExpendamount(expendamount.subtract(realAmountDecimal).doubleValue());
        if ("1".equals(mm.getStatus())) {
            // 股东会员消费总额
            BigDecimal stockMemberExpendamount = new BigDecimal(String.valueOf(mm.getStockMemberExpendamount()));
            mm.setStockMemberExpendamount(stockMemberExpendamount.subtract(realAmountDecimal).doubleValue());
        }
        memberManagementService.updateById(mm);

        // 模板消息
        try {
            String gzhOpenId = mm.getGzhOpenId();
            String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
            if (gzhOpenId == null) {
                log.info("发送退款通知模板推送失败，会员未绑定公众号");
            } else {
                StoreInfo store = storeInfoService.getById(storeId);
                if (store == null) {
                    log.info("发送退款通知模板推送失败，未查到店铺信息");
                } else {
                    String gzhAppId = store.getGzhAppId();
                    String gzhAppSecret = store.getGzhAppSecret();
                    if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                        log.info("发送退款通知模板推送失败，店铺未绑定公众号");
                    } else {
                        String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                        String result1 = HttpUtils.sendGet(url1);
                        JSONObject resultJson1 = JSON.parseObject(result1);
                        String errcode = resultJson1.getString("errcode");
                        if (errcode != null && !"0".equals(errcode)) {
                            log.info("发送退款通知模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                        } else {
                            String accessToken = resultJson1.getString("access_token");
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                            MsgTemplate msgTemplate = msgTemplateListService.getByTitle("退款通知", storeId);
                            String templateId = msgTemplate.getTemplateId();
                            util.refundNotice(templateId, gzhOpenId, order.getStoreName(), String.valueOf(order.getRealAmount()), order.getOrderCode(), sdf.format(new Date()), store.getXcxAppId(), "user/order/index?type=2", accessToken);

                            log.info("发送退款通知模板推送成功");
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("发送退款通知模板推送失败，发生异常", e);
        }

        if (dividendStock != null) {
            // 模板消息
            try {
                MemberManagement mm1 = memberManagementService.getById(dividendStock.getMemberId());
                String gzhOpenId = mm1.getGzhOpenId();
                if (gzhOpenId == null) {
                    log.info("发送股东会员退款通知模板推送失败，会员未绑定公众号");
                } else {
                    StoreInfo store = storeInfoService.getById(storeId);
                    if (store == null) {
                        log.info("发送股东会员退款通知模板推送失败，未查到店铺信息");
                    } else {
                        String bossGzhOpenId = storeInfoService.getBossGzhOpenId(storeId);
                        String gzhAppId = store.getGzhAppId();
                        String gzhAppSecret = store.getGzhAppSecret();
                        if (StringUtils.isEmpty(gzhAppId) || StringUtils.isEmpty(gzhAppSecret)) {
                            log.info("发送股东会员退款通知模板推送失败，店铺未绑定公众号");
                        } else {
                            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + gzhAppId + "&secret=" + gzhAppSecret;
                            String result1 = HttpUtils.sendGet(url1);
                            JSONObject resultJson1 = JSON.parseObject(result1);
                            String errcode = resultJson1.getString("errcode");
                            if (errcode != null && !"0".equals(errcode)) {
                                log.info("发送股东会员退款通知模板推送失败，获取accessToken返回值异常，错误码：{}", errcode);
                            } else {
                                String accessToken = resultJson1.getString("access_token");
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日 HH:mm");
                                MsgTemplate msgTemplate = msgTemplateListService.getByTitle("用户退款通知", storeId);
                                String templateId = msgTemplate.getTemplateId();
                                util.memberRefundNotice(templateId, gzhOpenId, mm.getName(), remark == null ? "" : remark, String.valueOf(order.getRealAmount()), sdf.format(new Date()), store.getXcxAppId(), "user/share/bonus", accessToken);

                                log.info("发送股东会员退款通知模板推送成功");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("发送股东会员退款通知模板推送失败，发生异常", e);
            }
        }

        return Result.OK("退单成功");
    }

    /**
     * 项目列表（用会员id查他关联的所有【有未核销商品或服务的项目】）
     * 参数：*memberId
     */
    @PostMapping("/listMemberProject")
    public Result<?> listMemberProject(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        if (StringUtils.isEmpty(memberId)) {
            return Result.error("参数不全");
        }
        List<Map<String, Object>> resultList=new ArrayList<>();

        List<Map<String, Object>> maps = cashierService.listMemberProject(map);
        for (Map<String, Object> vmap : maps) {
            System.out.println("lukasli:" + JSONObject.toJSONString(vmap));
            String name = vmap.get("content").toString();
            Object validateTime = vmap.get("validateTime");
            if (null == validateTime) {
                resultList.add(vmap);
                System.out.println("lukasli:" + "11");
            } else if (validateTime instanceof Date) {
                System.out.println("lukasli:" + "12");
                String cardName = TimeCardUtils.getCardName(name, (Date) validateTime);
                System.out.println("lukasli:" + cardName);
                vmap.put("content", cardName);
                if (!cardName.contains("已过期")){
                    resultList.add(vmap);
                }
            }


        }

        return Result.OK(resultList);
    }

    /**
     * 项目列表（用会员id查他关联的所有【有未核销商品或服务的项目】）
     * 参数：*memberId
     */
    @PostMapping("/listEx")
    public Result<?> listEx(
            @RequestParam(name = "type", defaultValue = "") String type,
            @RequestParam(name = "name", defaultValue = "") String name,
            HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        if (type.equals("1")) {
            List<CommodityInfo> commodityInfos = commodityManagementService.listEx(storeId, name);
            return Result.OK(commodityInfos);
        } else if (type.equals("1")) {
            List<ProjectManagement> projectManagements = projectManagementService.listEx(storeId, name);
            return Result.OK(projectManagements);
        }

        return Result.OK();
    }

    /**
     * 项目中的商品、服务列表
     * 参数：*orderProjectId
     */
    @PostMapping("/listMemberProjectShopAndServe")
    public Result<?> listMemberProjectShopAndServe(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String orderProjectId = map.get("orderProjectId") == null ? null : String.valueOf(map.get("orderProjectId"));
        if (StringUtils.isEmpty(orderProjectId)) {
            return Result.error("参数不全");
        }

        List<BaseOrderServiceWriteoff> serveList = baseOrderServiceWriteoffService.list(new QueryWrapper<BaseOrderServiceWriteoff>()
                .eq("order_project_id", orderProjectId));

        List<BaseOrderCommodityWriteoff> commodityList1 = baseOrderCommodityWriteoffService.list(new QueryWrapper<BaseOrderCommodityWriteoff>()
                .eq("order_project_id", orderProjectId));

        List<Object> commodityList = commodityList1.stream().map(o -> {
            Map<String, Object> m = ToolsUtils.objectToMap(o);
            m.put("type", "1");
            return m;
        }).collect(Collectors.toList());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<BaseOrderWriteoffRecord> writeoffRecordList = baseOrderWriteoffRecordService.list(new QueryWrapper<BaseOrderWriteoffRecord>()
                .eq("order_project_id", orderProjectId));
        for (BaseOrderWriteoffRecord record : writeoffRecordList) {
            JSONArray cList = JSONArray.parseArray(record.getCommodityListJsonStr());
            for (int i = 0; i < cList.size(); i++) {
                JSONObject jsonObject = cList.getJSONObject(i);
                jsonObject.put("type", "2");
                jsonObject.put("writeoffTime", sdf.format(jsonObject.getDate("writeoffTime")));
                commodityList.add(cList.getJSONObject(i));
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("serveList", serveList);
        result.put("commodityList", commodityList);
        return Result.OK(result);
    }

    /**
     * 核销（项目中的服务和商品）
     * 参数：*orderProjectId, commodityList[], serveList[](两个list至少一个有内容)
     * commodityList: *id, *num
     * serveList: *id, *staffId
     */
    @PostMapping("/consume")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> consume(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String orderProjectId = map.get("orderProjectId") == null ? null : String.valueOf(map.get("orderProjectId"));
        if (StringUtils.isEmpty(orderProjectId)) {
            return Result.error("参数不全");
        }
        List<Map<String, Object>> commodityList = (List<Map<String, Object>>) map.get("commodityList");
        List<Map<String, Object>> serveList = (List<Map<String, Object>>) map.get("serveList");
        if (CollectionUtils.isEmpty(commodityList) && CollectionUtils.isEmpty(serveList)) {
            return Result.error("核销内容不能为空");
        }

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        // 这里只是借用实体类的字段做核销记录，列表中内容意义与表中意义不完全相同
        List<BaseOrderCommodityWriteoff> commodityListRecord = new ArrayList<>();
        for (Map<String, Object> m : commodityList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            Integer num = m.get("num") == null ? 0 : Integer.parseInt(String.valueOf(m.get("num")));
            BaseOrderCommodityWriteoff bocw = baseOrderCommodityWriteoffService.getById(id);
            if (bocw.getStatus() == 1) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error("商品名称：" + bocw.getCommodityName() + "，已完全核销，不可继续核销");
            }
            if (num < 0 || num > bocw.getRemainQty()) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error("商品名称：" + bocw.getCommodityName() + "，核销数量不能为负数，且不能超过剩余数量");
            }
            bocw.setRemainQty(bocw.getRemainQty() - num);
            bocw.setWriteoffQty(bocw.getWriteoffQty() + num);
            bocw.setWriteoffTime(new Date());
            if ("员工".equals(sysUser.getRoleType())) {
                String userId = sysUser.getId();
                StaffManagement staff = staffManagementService.getOne(new QueryWrapper<StaffManagement>().eq("user_id", userId));
                bocw.setOperator(staff.getId());
                bocw.setOperatorName(staff.getName());
            } else {
                bocw.setOperatorName(sysUser.getRealname());
            }
            if (bocw.getRemainQty() == 0) {
                bocw.setStatus(1);
            }
            baseOrderCommodityWriteoffService.updateById(bocw);
            // 这里只是借用实体类的字段做核销记录，列表中内容意义与表中意义不完全相同
            bocw.setWriteoffQty(num);
            bocw.setRemainQty(null);
            bocw.setStatus(null);
            commodityListRecord.add(bocw);
        }

        List<BaseOrderServiceWriteoff> serveListRecord = new ArrayList<>();
        for (Map<String, Object> m : serveList) {
            String id = m.get("id") == null ? null : String.valueOf(m.get("id"));
            String serviceId = m.get("serviceId") == null ? null : String.valueOf(m.get("serviceId"));
            String staffId = m.get("staffId") == null ? null : String.valueOf(m.get("staffId"));
            BaseOrderServiceWriteoff bosw = baseOrderServiceWriteoffService.getById(id);
            if (bosw.getStatus() == 1) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Result.error("服务名称：" + bosw.getServiceName() + "，已核销，不可再次核销");
            }
            bosw.setWriteoffTime(new Date());
            StaffManagement staff = staffManagementService.getById(staffId);
            // 核销人员可以选择“无”，staffId可能为空
            if (staff != null) {
                // 服务提成
                bosw.setServicePersonId(staff.getId());
                bosw.setServicePerson(staff.getName());
                BigDecimal rewardMoney;
                BaseStaffStatusSpecial bsss = baseStaffStatusSpecialService.getOne(new QueryWrapper<BaseStaffStatusSpecial>()
                        .eq("staff_status_id", staff.getEmployeeId())
                        .eq("type", "3")
                        .eq("shop_id", bosw.getServiceId()));
                if (bsss != null) {
                    rewardMoney = new BigDecimal(String.valueOf(bsss.getRewardRate()));
                } else {
                    BaseStaffStatus bss = baseStaffStatusService.getById(staff.getEmployeeId());
                    rewardMoney = new BigDecimal(String.valueOf(bss.getServeReward()));
                }
                bosw.setServiceCommission(rewardMoney.doubleValue());

                // 服务提成
                BigDecimal serveMoney = new BigDecimal(String.valueOf(staff.getServeMoney()));
                staff.setServeMoney(serveMoney.add(rewardMoney).doubleValue());
                // 累计提成
                BigDecimal totalDeduction = new BigDecimal(String.valueOf(staff.getTotalDeduction()));
                staff.setTotalDeduction(totalDeduction.add(rewardMoney).doubleValue());
                // 总薪资
                BigDecimal totalSalary = new BigDecimal(String.valueOf(staff.getTotalSalary()));
                staff.setTotalSalary(totalSalary.add(rewardMoney).doubleValue());
                staffManagementService.updateById(staff);
            }
            if ("员工".equals(sysUser.getRoleType())) {
                String userId = sysUser.getId();
                StaffManagement staff1 = staffManagementService.getOne(new QueryWrapper<StaffManagement>().eq("user_id", userId));
                bosw.setOperator(staff1.getId());
                bosw.setOperatorName(staff1.getName());
            } else {
                bosw.setOperatorName(sysUser.getRealname());
            }
            bosw.setStatus(1);
            baseOrderServiceWriteoffService.updateById(bosw);
            serveListRecord.add(bosw);
        }

        // 生成核销记录
        BaseOrderProject bop = baseOrderProjectService.getById(orderProjectId);
        if (bop == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.error("未查到订单项目信息");
        }
        BaseOrder order = baseOrderService.getById(bop.getOrderId());
        if (order == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.error("未查到订单信息");
        }
        //Lukas add <--
        String projectId = bop.getProjectId();
        if (projectId != null) {
            ProjectManagement project = projectManagementService.getById(projectId);
            if (project != null) {
                if (bop.getValidateTime() == null) {
                   // bop.setIndate(project.getIndate());
                    //bop.setTimingWay(project.getTimingWay());
                    if (bop.getValidateTime() == null && "2".equals(bop.getTimingWay())) {
                        LocalDate l = LocalDate.now();
                        l=l.plusDays(Integer.parseInt(project.getIndate()));
                        bop.setValidateTime(DateUtils.local2util(l));
                    }
                }
            }
        }
        baseOrderProjectService.updateById(bop);
        // 更新到店时间
        List<CastCardRecord> list = castCardRecordService.list(new QueryWrapper<CastCardRecord>().eq("store_id", storeId).eq("member_id", order.getMemberId()));
        for (CastCardRecord r : list) {
            if (r.getEnterStoreDate() == null) {
                r.setEnterStoreDate(Date.from(Instant.now()));
                r.setEnterStoreStatus("Y");
            }
        }
        castCardRecordService.updateBatchById(list);
        //Lukas add -->
        BaseOrderWriteoffRecord bowr = new BaseOrderWriteoffRecord();
        bowr.setOrderId(bop.getOrderId());
        bowr.setOrderProjectId(orderProjectId);
        bowr.setOrderCode(order.getOrderCode());
        bowr.setOrderProjectName(bop.getProjectName());
        bowr.setMemberId(order.getMemberId());
        bowr.setMemberName(order.getMemberName());
        bowr.setMemberPhone(order.getMemberPhone());
        bowr.setStoreId(storeId);
        bowr.setServeListJsonStr(JSON.toJSONString(serveListRecord));
        bowr.setCommodityListJsonStr(JSON.toJSONString(commodityListRecord));
        baseOrderWriteoffRecordService.save(bowr);

        return Result.OK();
    }

    /**
     * 充值
     * 参数：*type(充值类型：会员余额充值/股本余额充值), *memberId(会员id), *amount(充值金额), staffId(提成归属员工id), *payType(支付方式：扫码支付、现金支付、微信记账、支付宝记账)
     */
    @PostMapping("/recharge")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> recharge(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String type = map.get("type") == null ? null : String.valueOf(map.get("type"));
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String amountStr = map.get("amount") == null ? null : String.valueOf(map.get("amount"));
        String payType = map.get("payType") == null ? null : String.valueOf(map.get("payType"));
        if (StringUtils.isEmpty(type) || StringUtils.isEmpty(memberId) || StringUtils.isEmpty(amountStr) || StringUtils.isEmpty(payType)) {
            return Result.error("参数不全");
        }
        String staffId = map.get("staffId") == null ? null : String.valueOf(map.get("staffId"));
        String outTradeNo = map.get("outTradeNo") == null ? null : String.valueOf(map.get("outTradeNo"));
        log.info("recharge outTradeNo:" + outTradeNo);
        BigDecimal amount = new BigDecimal(amountStr);
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return Result.error("充值金额需大于0");
        }

        MemberManagement mm = memberManagementService.getById(memberId);
        Double oldValue = mm.getBalance().doubleValue();
        Double newValue = null;
        if ("会员余额充值".equals(type)) {
            BigDecimal memberAmount = new BigDecimal(String.valueOf(mm.getAmount()));
            BigDecimal memberBalance = new BigDecimal(String.valueOf(mm.getBalance()));
            mm.setAmount(memberAmount.add(amount).doubleValue());
            mm.setBalance(memberBalance.add(amount).doubleValue());
            newValue = mm.getBalance();
            memberManagementService.updateById(mm);
            //TODO ??
        } else {
            StockManage sm = stockManageService.getById(mm.getMyStockId());
            if (sm == null) {
                return Result.error("非股东无法充值股本余额");
            }
            BigDecimal equityTotal = new BigDecimal(String.valueOf(sm.getEquityTotal()));
            BigDecimal equityBalance = new BigDecimal(String.valueOf(sm.getEquityBalance()));
            sm.setEquityTotal(equityTotal.add(amount).doubleValue());
            sm.setEquityBalance(equityBalance.add(amount).doubleValue());
            stockManageService.updateById(sm);
        }

        // 员工提成仅记录提成给谁，不在系统记录提成金额
        StaffManagement staff = staffManagementService.getById(staffId);

        // 充值记录
        BasePayOrder bpo = new BasePayOrder();
        bpo.setOrderCode(ToolsUtils.getBillNo("MR"));
        bpo.setRechargeType(payType);
        bpo.setRechargeAmount(amount.doubleValue());
        bpo.setMemberName(mm.getName());
        bpo.setMemberPhone(mm.getPhone());
        bpo.setPayType(payType);
        bpo.setPayTime(new Date());
        bpo.setName(type);
        bpo.setStoreId(storeId);
        bpo.setMemberId(memberId);
        bpo.setStockId(mm.getMyStockId());
        bpo.setPayCode(outTradeNo);
        if (staff != null) {
            bpo.setStaffId(staffId);
            bpo.setCommissionOwner(staff.getName());
        }
        basePayOrderService.save(bpo);
        //TODO lukasli 会员余额充值
        BalanceChangeRecord record = new BalanceChangeRecord();
//        record
        record.setStoreId(storeId);
        record.setMemberId(memberId);
        record.setMemberName(mm.getName());
        record.setMemberPhone(mm.getPhone());
        record.setChangeCode("C");
        record.setOrderNo(bpo.getOrderCode());
        record.setBalanceType("M");
        record.setPayCode("");

        record.setAmount(amount.doubleValue());
        record.setOldValue(oldValue);
        record.setNewValue(newValue);
        record.setTradeMode("");
        record.setTradeTime(Date.from(Instant.now()));
        record.setRemark(bpo.getId());
        record.setId(null);
        record.setCreateBy("");
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateBy(null);
        record.setUpdateBy(null);

        blanceChangeRecordService.save(record);

        return Result.OK("充值成功");
    }

    @PostMapping("/saobeiPay")
    public Result<?> saobeiPay(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        log.info("saobeiPay开始调用...");
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            log.info("saobeiPay  请先到首页选择店铺");
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            log.info("saobeiPay  店铺已过期，续费后才可操作");
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String authNo = map.get("authNo") == null ? null : String.valueOf(map.get("authNo"));
        String amountStr = map.get("amount") == null ? null : String.valueOf(map.get("amount"));
        if (StringUtils.isEmpty(authNo) || StringUtils.isEmpty(amountStr)) {
            log.info("saobeiPay  参数不全");
            return Result.error("参数不全");
        }

        StoreInfo store = storeInfoService.getById(storeId);
        if (store == null) {
            log.info("saobeiPay  店铺不存在");
            return Result.error("店铺不存在");
        }
        String saobeiMerchantNo = store.getSaobeiMerchantNo();
        String saobeiTerminalId = store.getSaobeiTerminalId();
        String saobeiAccessToken = store.getSaobeiAccessToken();
        if (StringUtils.isEmpty(saobeiMerchantNo) || StringUtils.isEmpty(saobeiTerminalId) || StringUtils.isEmpty(saobeiAccessToken)) {
            log.info("saobeiPay  店铺还未绑定支付");
            return Result.error("店铺还未绑定支付");
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

        // 前端传来的金额单位已经是（分）了
//      BigDecimal amount = new BigDecimal(amountStr);
//      String totalFee = String.valueOf(amount.multiply(new BigDecimal("100")).intValue());
        SaobeiBarcodePayResponse barcodePayResponse = Saobei.barcodepay(saobeiAccessToken, saobeiMerchantNo, saobeiTerminalId, authNo, sdf.format(new Date()), amountStr);
        Map<String, Object> result = new HashMap<>();
        result.put("outTradeNo", barcodePayResponse.getOut_trade_no());
        result.put("resultCode", barcodePayResponse.getResult_code());
        result.put("returnMsg", barcodePayResponse.getReturn_msg());
        log.info("saobeiPay  OK");
        return Result.OK(result);
    }

    @PostMapping("/saobeiQuery")
    public Result<?> saobeiQuery(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        log.info("saobeiQuery  开始调用...");
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            log.info("saobeiQuery  请先到首页选择店铺");
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            log.info("saobeiQuery  店铺已过期，续费后才可操作");
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String outTradeNo = map.get("outTradeNo") == null ? null : String.valueOf(map.get("outTradeNo"));
        if (StringUtils.isEmpty(outTradeNo)) {
            log.info("saobeiQuery  参数不全");
            return Result.error("参数不全");
        }

        StoreInfo store = storeInfoService.getById(storeId);
        if (store == null) {
            log.info("saobeiQuery  店铺不存在");
            return Result.error("店铺不存在");
        }
        String saobeiMerchantNo = store.getSaobeiMerchantNo();
        String saobeiTerminalId = store.getSaobeiTerminalId();
        String saobeiAccessToken = store.getSaobeiAccessToken();
        if (StringUtils.isEmpty(saobeiMerchantNo) || StringUtils.isEmpty(saobeiTerminalId) || StringUtils.isEmpty(saobeiAccessToken)) {
            log.info("saobeiQuery  店铺还未绑定支付");
            return Result.error("店铺还未绑定支付");
        }

        SaobeiTradeQueryResponse queryResponse = Saobei.query(saobeiAccessToken, saobeiMerchantNo, saobeiTerminalId, outTradeNo);
        Map<String, Object> result = new HashMap<>();
        result.put("outTradeNo", queryResponse.getOut_trade_no());
        result.put("resultCode", queryResponse.getResult_code());
        result.put("returnMsg", queryResponse.getReturn_msg());
        log.info("saobeiQuery  OK");
        return Result.OK(result);
    }

    /**
     * 退款
     * 参数： *memberId(会员id), *amount(充值金额), staffId(提成归属员工id)
     */
    @PostMapping("/tuikuan")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> tuikuan(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String memberId = map.get("memberId") == null ? null : String.valueOf(map.get("memberId"));
        String amountStr = map.get("amount") == null ? null : String.valueOf(map.get("amount"));
        String balanceType = map.get("type") == null ? null : String.valueOf(map.get("type"));
        if (StringUtils.isEmpty(memberId) || StringUtils.isEmpty(amountStr) || StringUtils.isEmpty(balanceType)) {
            return Result.error("参数不全");
        }
//        String staffId = map.get("staffId") == null ? null : String.valueOf(map.get("staffId"));
        String outTradeNo = map.get("outTradeNo") == null ? null : String.valueOf(map.get("outTradeNo"));

        log.info("recharge outTradeNo:" + outTradeNo);
        MemberManagement mm = memberManagementService.getById(memberId);
        if (mm == null) {
            return Result.error("没有会员！");
        }
        BigDecimal amount = new BigDecimal(amountStr);
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return Result.error("退款金额需大于0");
        }
        BalanceChangeRecord record = new BalanceChangeRecord();
        record.setMemberId(memberId);
        record.setMemberName(mm.getName());
        record.setMemberPhone(mm.getPhone());
        record.setChangeCode("T");
        record.setStoreId(storeId);
        record.setAmount(amount.doubleValue());
        balanceType=balanceType.toUpperCase();

        if ("M".equals(balanceType)) {
            BigDecimal balance = BigDecimal.valueOf(mm.getBalance());
            Double newValue = balance.subtract(amount).doubleValue();
            if (newValue < 0) {
                return Result.error("退款金额需小于会员余额");
            }
            mm.setBalance(newValue);
            memberManagementService.updateById(mm);
            record.setBalanceType("M");

            record.setOldValue(mm.getBalance());
            record.setNewValue(newValue);

        } else if ("S".equals(balanceType)) {
            List<StockManage> list = stockManageService.list(new QueryWrapper<StockManage>().eq("store_id", storeId).eq("member_id", memberId));
            if (list.size() != 1) {

            } else {
                StockManage stockManage = list.get(0);
                Double equityBalance = stockManage.getEquityBalance();
                if (equityBalance.doubleValue() < amount.doubleValue()) {
                    return Result.error("退款金额需大于0");
                }
                record.setBalanceType("S");
                record.setOldValue(equityBalance);
                record.setNewValue(equityBalance.doubleValue() - amount.doubleValue());

                stockManage.setEquityBalance(equityBalance-amount.doubleValue());
                stockManageService.updateById(stockManage);

            }
        }

        record.setOrderNo(ToolsUtils.getBillNo("TK"));
        record.setPayCode("");
        record.setTradeMode("");
        record.setTradeTime(Date.from(Instant.now()));
        record.setRemark("");
        record.setId(null);
        record.setCreateBy("");
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateBy(null);
        record.setUpdateBy(null);
        blanceChangeRecordService.save(record);


     /*   MemberManagement member = memberManagementService.getById(memberId);
        Double balance = member.getBalance();
        member.setBalance(balance-amount.doubleValue());
        memberManagementService.updateById(member);*/

        return Result.OK("退款成功");
    }

    @ApiOperation(value = "收银台-获得提成", notes = "收银台-获得提成")
    @PostMapping("/getReward")
    public Result<?> getReward(@RequestBody Map<String, Object> map, HttpServletRequest req) {
        String token = TokenUtils.getTokenByRequest(req);
        String storeId = (String) redisUtils.get(RedisUtils.storeId + token);
        if (oConvertUtils.isEmpty(storeId)) {
            return Result.error("请先到首页选择店铺");
        }
        if (storeId.contains("过期")) {
            return Result.error("店铺已过期，续费后才可操作");
        }
        map.put("storeId", storeId);
        String staffId = map.get("staffId") == null ? null : String.valueOf(map.get("staffId"));
        String relateId = map.get("relateId") == null ? null : String.valueOf(map.get("relateId"));
        //String workActor = map.get("workActor") == null ? null : String.valueOf(map.get("workActor"));

//        String storeId,String staffId,String relateId,String workActor


        if (StringUtils.isBlank(staffId)) {
            return Result.error("缺少员工标识");
        }
        if (StringUtils.isBlank(relateId)) {
            return Result.error("缺少产品标识");
        }

        StaffManagement staff = staffManagementService.getById(staffId);
        String employeeId = staff.getEmployeeId();
        if (employeeId != null) {
            QueryWrapper<StoreStaffReward> storeStaffRewardQueryWrapper = new QueryWrapper<>();

            List<StoreStaffReward> list = storeStaffRewardService.list(storeStaffRewardQueryWrapper
                            .eq("store_id", storeId)
                            .eq("trade_actor", employeeId)
                            .eq("relate_id", relateId)
                    //          .eq("work_actor", workActor)
            );


            return list.size() > 0 ? Result.OK(list) : Result.OK();
        }
        //  BaseStaffStatus staffStatus = baseStaffStatusService.getById(id);


        return Result.OK();
    }

    public StoreStaffReward getReward(String storeId, String staffId, String relateId, String workActor) {


        StoreStaffReward result = null;
        StaffManagement staff = staffManagementService.getById(staffId);
        String employeeId = staff.getEmployeeId();
        if (employeeId != null) {
            QueryWrapper<StoreStaffReward> storeStaffRewardQueryWrapper = new QueryWrapper<>();

            List<StoreStaffReward> list = storeStaffRewardService.list(storeStaffRewardQueryWrapper
                    .eq("store_id", storeId)
                    .eq("trade_actor", employeeId)
                    .eq("relate_id", relateId)
                    .eq("work_actor", workActor)
            );

//            if(staff.getEmployee().contains("技师")){
//                if(list.size()>1){
//                    Collections.sort(list, new Comparator<StoreStaffReward>() {
//                        @Override
//                        public int compare(StoreStaffReward o1, StoreStaffReward o2) {
//                            Integer i1 = Integer.valueOf(o1.getWorkActor());
//                            Integer i2 = Integer.valueOf(o2.getWorkActor());
//
//                            return i2.intValue()-i1.intValue();
//                        }
//                    });
//                }
//            }


            return list.size() > 0 ? list.get(0) : null;
        }
        //  BaseStaffStatus staffStatus = baseStaffStatusService.getById(id);


        return null;
    }

    private List<String> getHighStock(String storeId, String stockId) {
        List<String> list = new ArrayList<>();
        StockManage stock = stockManageService.getById(stockId);
        if (stock != null) {
            String memberId = stock.getMemberId();
            if (memberId != null) {
                MemberManagement member = memberManagementService.getById(memberId);

                String stockId1 = member.getStockId();
                if (StringUtils.isEmpty(stockId1)) {
                    StockManage byId = stockManageService.getById(stockId1);
                    if (byId != null) {
                        list.add(stockId1);
                    }
                }
                String myStockId = member.getMyStockId();
                if (StringUtils.isEmpty(myStockId)) {
                    StockManage byId = stockManageService.getById(myStockId);
                    if (byId != null) {
                        list.add(myStockId);
                    }
                }
            }
        }

        return list;
    }

    private void giveHighStock(String storeId, String stockId, BigDecimal realAmountDecimal) {
        List<String> highStocks = getHighStock(storeId, stockId);
        if (highStocks.size() > 0) {
            String s = highStocks.get(0);
            StockManage stock = stockManageService.getById(s);
            String shareholdersHousekeeperId = stock.getShareholdersHousekeeperId();

            if (StringUtils.isBlank(shareholdersHousekeeperId) && staffManagementService.getById(shareholdersHousekeeperId) != null) {
                StaffManagement dividendStaff = staffManagementService.getById(shareholdersHousekeeperId);
                BigDecimal ratio = new BigDecimal(String.valueOf(stock.getShareholdersRatio()));
                BigDecimal staffShareMoney = realAmountDecimal.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                // 分红
                BigDecimal totalShare = new BigDecimal(String.valueOf(dividendStaff.getTotalShare()));
                dividendStaff.setTotalShare(totalShare.add(staffShareMoney).doubleValue());
                // 总薪资
                BigDecimal totalSalary = new BigDecimal(String.valueOf(dividendStaff.getTotalSalary()));
                dividendStaff.setTotalSalary(totalSalary.add(staffShareMoney).doubleValue());
                staffManagementService.updateById(dividendStaff);


                Double indirectProrateDividends = stock.getIndirectProrateDividends();
                if (indirectProrateDividends == null) {
                    indirectProrateDividends = 0.0;
                }
                BigDecimal inBigDecimal = new BigDecimal(indirectProrateDividends);
                BigDecimal subtract = realAmountDecimal.subtract(staffShareMoney);
                indirectProrateDividends = inBigDecimal.add(subtract).doubleValue();
                stock.setIndirectDividend(indirectProrateDividends);
                stockManageService.updateById(stock);

            } else {
                Double indirectProrateDividends = stock.getIndirectProrateDividends();
                if (indirectProrateDividends == null) {
                    indirectProrateDividends = 0.0;
                }
                BigDecimal inBigDecimal = new BigDecimal(indirectProrateDividends);

                indirectProrateDividends = inBigDecimal.add(realAmountDecimal).doubleValue();
                stock.setIndirectDividend(indirectProrateDividends);
                stockManageService.updateById(stock);

            }

        }

    }

    private void giveStaffMoney(String staffId, String type, BigDecimal realAmountDecimal) {
        StaffManagement staff = staffManagementService.getById(staffId);
        if (staff == null) {
            log.warn("staff[id{}] is null ", staffId);
            return;
        }
        if ("1".equals(type)) {
            Double sellMoney = staff.getSellMoney();
            if (sellMoney == null) {
                sellMoney = 0.0;
            }
            sellMoney = plus(sellMoney, realAmountDecimal);
            staff.setSellMoney(sellMoney);
        } else {
            Double serveMoney = staff.getServeMoney();
            if (serveMoney == null) {
                serveMoney = 0.0;
            }
            serveMoney = plus(serveMoney, realAmountDecimal);
            staff.setSellMoney(serveMoney);
        }

        staffManagementService.updateById(staff);
    }

    private Double plus(Double money, BigDecimal realAmountDecimal) {
        return money.doubleValue() + realAmountDecimal.doubleValue();
    }
}

